diff --git a/10/umbraco-cms/.gitbook.yaml b/10/umbraco-cms/.gitbook.yaml deleted file mode 100644 index 4532727be5e..00000000000 --- a/10/umbraco-cms/.gitbook.yaml +++ /dev/null @@ -1,11 +0,0 @@ -root: ./ - -​structure: - readme: README.md - summary: SUMMARY.md - -redirects: - tutorials/add-azure-active-directory-authentication: tutorials/add-microsoft-entra-id-authentication.md - tutorials/editors-manual/working-with-content/rich-text-editor: tutorials/editors-manual/working-with-content.md - extending/property-editors/build-a-block-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md - tutorials/creating-and-distributing-a-package: extending/packages/creating-a-package.md diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Backoffice_UI_API.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Backoffice_UI_API.png deleted file mode 100644 index 64a50d3ce6c..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Backoffice_UI_API.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Dashboards.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Dashboards.png deleted file mode 100644 index 3521daba379..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Dashboards.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Health_Checks.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Health_Checks.png deleted file mode 100644 index 5524b73c767..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Health_Checks.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Packages.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Packages.png deleted file mode 100644 index 126a7bb65a1..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Packages.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Property_Editors.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Property_Editors.png deleted file mode 100644 index 555d76dfbee..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Property_Editors.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png deleted file mode 100644 index c313d797d13..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals.png deleted file mode 100644 index b9010a07979..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Composing.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Composing.png deleted file mode 100644 index b10aa4d8651..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Composing.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Controllers.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Controllers.png deleted file mode 100644 index 56e75d65963..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Controllers.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Custom_Routing.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Custom_Routing.png deleted file mode 100644 index 4ac0bbf95a0..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Custom_Routing.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Data_Persistence.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Data_Persistence.png deleted file mode 100644 index ac956eafbbc..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Data_Persistence.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Routing.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Routing.png deleted file mode 100644 index 8ea13956765..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Routing.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Services_and_Helpers.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Services_and_Helpers.png deleted file mode 100644 index 724c96c54d3..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Services_and_Helpers.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install.png deleted file mode 100644 index 01beb93f1e6..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_API_Documentation.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_API_Documentation.png deleted file mode 100644 index 7164d6542f9..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_API_Documentation.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Caching.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Caching.png deleted file mode 100644 index 41b02fe3c4a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Caching.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Configuration.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Configuration.png deleted file mode 100644 index 35d43482ffd..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Configuration.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Notifications.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Notifications.png deleted file mode 100644 index 5790d353ba3..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Notifications.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png deleted file mode 100644 index 61b11658050..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Routing_and_Controllers.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Routing_and_Controllers.png deleted file mode 100644 index 8529aae789f..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Routing_and_Controllers.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching.png deleted file mode 100644 index 36feaf25719..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Security.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Security.png deleted file mode 100644 index a9bbebbbea0..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Security.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Templating.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Templating.png deleted file mode 100644 index 94df11bb19a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Templating.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials (1).png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials (1).png deleted file mode 100644 index f96fffc1c43..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials (1).png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials.png deleted file mode 100644 index f96fffc1c43..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Basic_Website.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Basic_Website.png deleted file mode 100644 index 45f98513f48..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Basic_Website.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Dashboard.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Dashboard.png deleted file mode 100644 index 49a429c95da..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Dashboard.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Error_Page.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Error_Page.png deleted file mode 100644 index f95896c57ef..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Error_Page.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Property_Editor.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Property_Editor.png deleted file mode 100644 index fb540e90782..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Property_Editor.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Views_Block_List.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Views_Block_List.png deleted file mode 100644 index 8b0c842229f..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Views_Block_List.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Google_Authentification.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Google_Authentification.png deleted file mode 100644 index 3f678967f20..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Google_Authentification.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Member_Reg_and_login.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Member_Reg_and_login.png deleted file mode 100644 index 66dc300073f..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Member_Reg_and_login.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup.png deleted file mode 100644 index a6e56cde534..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Multilingual_Website.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Multilingual_Website.png deleted file mode 100644 index 92cc76d753f..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Multilingual_Website.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Umbraco_Forms_and_Zapier.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Umbraco_Forms_and_Zapier.png deleted file mode 100644 index ccffbc3c872..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Umbraco_Forms_and_Zapier.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png b/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png deleted file mode 100644 index aed96f1fd6a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Embed-Button (1).png b/10/umbraco-cms/.gitbook/assets/Embed-Button (1).png deleted file mode 100644 index 82a0371675a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Embed-Button (1).png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Embed-Button.png b/10/umbraco-cms/.gitbook/assets/Embed-Button.png deleted file mode 100644 index 82a0371675a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Embed-Button.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Embed-YouTube (1).png b/10/umbraco-cms/.gitbook/assets/Embed-YouTube (1).png deleted file mode 100644 index 558fd5b631a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Embed-YouTube (1).png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Embed-YouTube.png b/10/umbraco-cms/.gitbook/assets/Embed-YouTube.png deleted file mode 100644 index 558fd5b631a..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Embed-YouTube.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/ModelsBuilderDisabledOnProduction.png b/10/umbraco-cms/.gitbook/assets/ModelsBuilderDisabledOnProduction.png deleted file mode 100644 index 14492e61ab3..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/ModelsBuilderDisabledOnProduction.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/ReferencedDataTypes.PNG b/10/umbraco-cms/.gitbook/assets/ReferencedDataTypes.PNG deleted file mode 100644 index a0d6f1abbb9..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/ReferencedDataTypes.PNG and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/TemplatedCannotBeEditedWhenRuntimeIsProduction.png b/10/umbraco-cms/.gitbook/assets/TemplatedCannotBeEditedWhenRuntimeIsProduction.png deleted file mode 100644 index f6379dc05f6..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/TemplatedCannotBeEditedWhenRuntimeIsProduction.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Top_hero_for_com_1500x500px2.png b/10/umbraco-cms/.gitbook/assets/Top_hero_for_com_1500x500px2.png deleted file mode 100644 index 10ef4a25841..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Top_hero_for_com_1500x500px2.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/Using_Dictionary_Value.jpg b/10/umbraco-cms/.gitbook/assets/Using_Dictionary_Value.jpg deleted file mode 100644 index 71aafdbe493..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/Using_Dictionary_Value.jpg and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/api-docs-image.png b/10/umbraco-cms/.gitbook/assets/api-docs-image.png deleted file mode 100644 index 215f4191aff..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/api-docs-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/backoffice-ui-images.png b/10/umbraco-cms/.gitbook/assets/backoffice-ui-images.png deleted file mode 100644 index 52949da0a85..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/backoffice-ui-images.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/block-list-image.png b/10/umbraco-cms/.gitbook/assets/block-list-image.png deleted file mode 100644 index 7e2462aff88..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/block-list-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/c-routing-image.png b/10/umbraco-cms/.gitbook/assets/c-routing-image.png deleted file mode 100644 index 6ef562a2139..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/c-routing-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/caching-image.png b/10/umbraco-cms/.gitbook/assets/caching-image.png deleted file mode 100644 index 16c31b7d1fd..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/caching-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/code-image.png b/10/umbraco-cms/.gitbook/assets/code-image.png deleted file mode 100644 index 37060e9deb1..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/code-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/composing-image.png b/10/umbraco-cms/.gitbook/assets/composing-image.png deleted file mode 100644 index 84114e14334..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/composing-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/controllers-image.png b/10/umbraco-cms/.gitbook/assets/controllers-image.png deleted file mode 100644 index 18d83567ff4..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/controllers-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/create-website-image.png b/10/umbraco-cms/.gitbook/assets/create-website-image.png deleted file mode 100644 index 950d99bb992..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/create-website-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/dashboards-image.png b/10/umbraco-cms/.gitbook/assets/dashboards-image.png deleted file mode 100644 index ae820772b31..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/dashboards-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/data.png b/10/umbraco-cms/.gitbook/assets/data.png deleted file mode 100644 index 00b9bd36c20..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/data.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/datap-image.png b/10/umbraco-cms/.gitbook/assets/datap-image.png deleted file mode 100644 index 33c7e6e117c..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/datap-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/design.png b/10/umbraco-cms/.gitbook/assets/design.png deleted file mode 100644 index f35e9ca42fd..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/design.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/deviantart-embedded-media (1).png b/10/umbraco-cms/.gitbook/assets/deviantart-embedded-media (1).png deleted file mode 100644 index 534b766e947..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/deviantart-embedded-media (1).png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/deviantart-embedded-media.png b/10/umbraco-cms/.gitbook/assets/deviantart-embedded-media.png deleted file mode 100644 index 534b766e947..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/deviantart-embedded-media.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/docs-style-hero.png b/10/umbraco-cms/.gitbook/assets/docs-style-hero.png deleted file mode 100644 index a63f4894788..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/docs-style-hero.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/error-pages-image.png b/10/umbraco-cms/.gitbook/assets/error-pages-image.png deleted file mode 100644 index a54961025b6..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/error-pages-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/google-auth-image.png b/10/umbraco-cms/.gitbook/assets/google-auth-image.png deleted file mode 100644 index e3aa84cc8a4..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/google-auth-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/healthchecks-image.png b/10/umbraco-cms/.gitbook/assets/healthchecks-image.png deleted file mode 100644 index 954ba2acfb7..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/healthchecks-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/member-image.png b/10/umbraco-cms/.gitbook/assets/member-image.png deleted file mode 100644 index 7f90741a30b..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/member-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/multilingual-site.png b/10/umbraco-cms/.gitbook/assets/multilingual-site.png deleted file mode 100644 index 6a0121bf766..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/multilingual-site.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/multisite-image.png b/10/umbraco-cms/.gitbook/assets/multisite-image.png deleted file mode 100644 index 78e415c519f..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/multisite-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/notifications-image.png b/10/umbraco-cms/.gitbook/assets/notifications-image.png deleted file mode 100644 index 136257d2190..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/notifications-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/packages-image.png b/10/umbraco-cms/.gitbook/assets/packages-image.png deleted file mode 100644 index 796fe6fee73..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/packages-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/property-image.png b/10/umbraco-cms/.gitbook/assets/property-image.png deleted file mode 100644 index b36657bc7db..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/property-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/reversed-heart-hero.png b/10/umbraco-cms/.gitbook/assets/reversed-heart-hero.png deleted file mode 100644 index 76011a1be13..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/reversed-heart-hero.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/routing-image.png b/10/umbraco-cms/.gitbook/assets/routing-image.png deleted file mode 100644 index 19eda19e188..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/routing-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/searching-image.png b/10/umbraco-cms/.gitbook/assets/searching-image.png deleted file mode 100644 index e5651e643a1..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/searching-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/security-imag.png b/10/umbraco-cms/.gitbook/assets/security-imag.png deleted file mode 100644 index a47343805a9..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/security-imag.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/services-image.png b/10/umbraco-cms/.gitbook/assets/services-image.png deleted file mode 100644 index 7a6268434f9..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/services-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/setup-image.png b/10/umbraco-cms/.gitbook/assets/setup-image.png deleted file mode 100644 index 612f4b29011..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/setup-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/setup.png b/10/umbraco-cms/.gitbook/assets/setup.png deleted file mode 100644 index 8b85307ba8e..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/setup.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/starter-kit-image.png b/10/umbraco-cms/.gitbook/assets/starter-kit-image.png deleted file mode 100644 index 150bd541804..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/starter-kit-image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/trees.image.png b/10/umbraco-cms/.gitbook/assets/trees.image.png deleted file mode 100644 index 4579d6b0849..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/trees.image.png and /dev/null differ diff --git a/10/umbraco-cms/.gitbook/assets/zapier-image.png b/10/umbraco-cms/.gitbook/assets/zapier-image.png deleted file mode 100644 index 0589efbfe34..00000000000 Binary files a/10/umbraco-cms/.gitbook/assets/zapier-image.png and /dev/null differ diff --git a/10/umbraco-cms/README.md b/10/umbraco-cms/README.md deleted file mode 100644 index bac7014713c..00000000000 --- a/10/umbraco-cms/README.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: Your main resource when building and managing an Umbraco CMS website. ---- - -# Umbraco CMS Documentation - -Umbraco CMS is a flexible and editor-friendly Content Management System (CMS) that allows you to create beautiful and modern websites. Use the latest version of .NET, integrate with your favorite services, and help your customers launch a website tailored to their specific needs. - -Learn much more about Umbraco CMS and get an overview of the top features on [Umbraco.com](https://umbraco.com/products/umbraco-cms/). - -
FundamentalsLearn the basics of working with Umbraco CMS. How to install and setup your first site is also included in this section.Top_hero_for_com_1500x500px2.pngget-to-know-umbraco.md
Install Umbraco CMSReady to get started with Umbraco? Head over to the Setup section to learn how to install Umbraco CMS.docs-style-hero.pnginstall
TutorialsFind details step-by-step guides on everything from building a site from scratch to implementing a custom maintenance page.reversed-heart-hero.pngoverview.md
- -{% embed url="https://www.youtube-nocookie.com/embed/Yu29dE-0OoI" %} -Watch this tutorial on how to get started building your first Umbraco CMS website. -{% endembed %} - -The Umbraco CMS documentation caters to both experienced Umbraco/.NET developers and beginners with guides and high-level articles. - -{% content-ref url="tutorials/creating-a-basic-website/" %} -[creating-a-basic-website](tutorials/creating-a-basic-website/) -{% endcontent-ref %} - -{% content-ref url="reference/configuration/" %} -[configuration](reference/configuration/) -{% endcontent-ref %} - -{% content-ref url="fundamentals/setup/requirements.md" %} -[requirements.md](fundamentals/setup/requirements.md) -{% endcontent-ref %} - -{% content-ref url="reference/notifications/" %} -[notifications](reference/notifications/) -{% endcontent-ref %} diff --git a/10/umbraco-cms/SUMMARY.md b/10/umbraco-cms/SUMMARY.md deleted file mode 100644 index 8ce726d0d4f..00000000000 --- a/10/umbraco-cms/SUMMARY.md +++ /dev/null @@ -1,461 +0,0 @@ -# Table of contents - -* [Umbraco CMS Documentation](README.md) -* [Legacy Documentation](legacy-documentation/README.md) - * [Umbraco 11 Documentation](https://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions) - * [Umbraco 8 Documentation](https://our.umbraco.com/documentation/) - * [Umbraco 7 Documentation](https://our.umbraco.com/documentation/) -* [Release Notes](https://our.umbraco.com/download/releases/) -* [Contribute](https://docs.umbraco.com/contributing) -* [Sustainability Best Practices](https://docs.umbraco.com/sustainability-best-practices/) - -## Fundamentals - -* [Get to know Umbraco](fundamentals/get-to-know-umbraco.md) -* [Setup](fundamentals/setup/README.md) - * [Requirements](fundamentals/setup/requirements.md) - * [Installation](fundamentals/setup/install/README.md) - * [Install using .NET CLI](fundamentals/setup/install/install-umbraco-with-templates.md) - * [Install using Visual Studio](fundamentals/setup/install/visual-studio.md) - * [Local IIS With Umbraco](fundamentals/setup/install/iis.md) - * [Install Umbraco With Visual Studio Code](fundamentals/setup/install/install-umbraco-with-vs-code.md) - * [Installing Nightly Builds](fundamentals/setup/install/installing-nightly-builds.md) - * [Running Umbraco On Linux/macOS](fundamentals/setup/install/running-umbraco-on-linux-macos.md) - * [Unattended Installs](fundamentals/setup/install/unattended-install.md) - * [Upgrade your project](fundamentals/setup/upgrading/README.md) - * [Version Specific Upgrades](fundamentals/setup/upgrading/version-specific/README.md) - * [Upgrade from Umbraco 8 to Umbraco 10](fundamentals/setup/upgrading/version-specific/upgrade-from-8-to-latest.md) - * [Migrate content to Umbraco 8](fundamentals/setup/upgrading/version-specific/migrate-content-to-umbraco-8.md) - * [Minor upgrades for Umbraco 8](fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-8.md) - * [Upgrade to Umbraco 7](fundamentals/setup/upgrading/version-specific/upgrade-to-umbraco-7.md) - * [Minor upgrades for Umbraco 7](fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-7.md) - * [Server setup](fundamentals/setup/server-setup/README.md) - * [Running Umbraco On Azure Web Apps](fundamentals/setup/server-setup/azure-web-apps.md) - * [Hosting Umbraco in IIS](fundamentals/setup/server-setup/iis.md) - * [File And Folder Permissions](fundamentals/setup/server-setup/permissions.md) - * [Runtime Modes](fundamentals/setup/server-setup/runtime-modes.md) - * [Running Umbraco in Docker](fundamentals/setup/server-setup/running-umbraco-in-docker.md) - * [Umbraco in Load Balanced Environments](fundamentals/setup/server-setup/load-balancing/README.md) - * [Load Balancing Azure Web Apps](fundamentals/setup/server-setup/load-balancing/azure-web-apps.md) - * [Standalone File System](fundamentals/setup/server-setup/load-balancing/file-system-replication.md) - * [Advanced Techniques With Flexible Load Balancing](fundamentals/setup/server-setup/load-balancing/flexible-advanced.md) - * [Logging With Load Balancing](fundamentals/setup/server-setup/load-balancing/logging.md) -* [Backoffice](fundamentals/backoffice/README.md) - * [Sections](fundamentals/backoffice/sections.md) - * [Property Editors](fundamentals/backoffice/property-editors/README.md) - * [Built-in Property Editors](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md) - * [Checkbox List](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md) - * [Color Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md) - * [Content Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md) - * [DateTime](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md) - * [Date](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md) - * [Decimal](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md) - * [Email Address](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md) - * [Eye Dropper Color Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md) - * [File Upload](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md) - * [Image Cropper](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md) - * [Label](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md) - * [List View](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/listview.md) - * [Markdown Editor](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md) - * [Media Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md) - * [Media Picker (Legacy)](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker.md) - * [Member Group Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md) - * [Member Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md) - * [Multi Url Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md) - * [Multinode Treepicker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multinode-treepicker.md) - * [Repeatable Textstrings](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md) - * [Nested Content (Legacy)](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/nested-content.md) - * [Numeric](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md) - * [Radiobutton List](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md) - * [Slider](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/slider.md) - * [Tags](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/tags.md) - * [Textarea](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textarea.md) - * [Textbox](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textbox.md) - * [Toggle](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/true-false.md) - * [User Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/user-picker.md) - * [Block Editors](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md) - * [Block Grid](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md) - * [Block List](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md) - * [Build a Custom View for a Block](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/build-custom-view-for-blocks.md) - * [Configuring Block Editor Label Properties](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration.md) - * [Dropdown](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md) - * [Grid Layout (Legacy)](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/README.md) - * [What Are Grid Layouts?](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/what-are-grid-layouts.md) - * [Configuring The Grid Layout](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/configuring-the-grid-layout-datatype.md) - * [Settings And Styling](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/settings-and-styles.md) - * [Grid Editors](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors.md) - * [Build Your Own Editor](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/build-your-own-editor.md) - * [Rendering Grid In a Template](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/render-grid-in-template.md) - * [Grid Layout Best Practices](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-layout-best-practices.md) - * [Add Values Programmatically](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/add-value-programmatically.md) - * [Rich Text Editor](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md) - * [Rich Text Editor Configuration](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md) - * [Rich Text Editor Styles](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/rte-styles.md) - * [Login](fundamentals/backoffice/login.md) - * [Content Templates](fundamentals/backoffice/content-templates.md) - * [Infinite Editing](fundamentals/backoffice/infinite-editing.md) - * [Log Viewer](fundamentals/backoffice/logviewer.md) - * [Language Variants](fundamentals/backoffice/variants.md) - * [Settings Dashboards](fundamentals/backoffice/settings-dashboards.md) -* [Data](fundamentals/data/README.md) - * [Defining Content](fundamentals/data/defining-content/README.md) - * [Default Document Types](fundamentals/data/defining-content/default-document-types.md) - * [Creating Media](fundamentals/data/creating-media/README.md) - * [Default Data/Media Types](fundamentals/data/creating-media/default-media-types.md) - * [Members](fundamentals/data/members.md) - * [Data Types](fundamentals/data/data-types/README.md) - * [Default Data Types](fundamentals/data/data-types/default-data-types.md) - * [Scheduled Publishing](fundamentals/data/scheduled-publishing.md) - * [Using Tabs](fundamentals/data/adding-tabs.md) - * [Users](fundamentals/data/users.md) - * [Relations](fundamentals/data/relations.md) - * [Dictionary Items](fundamentals/data/dictionary-items.md) - * [Content Version Cleanup](fundamentals/data/content-version-cleanup.md) -* [Design](fundamentals/design/README.md) - * [Templates](fundamentals/design/templates/README.md) - * [Basic Razor Syntax](fundamentals/design/templates/basic-razor-syntax.md) - * [Named Sections](fundamentals/design/templates/named-sections.md) - * [Razor Cheatsheet](fundamentals/design/templates/razor-cheatsheet.md) - * [Rendering Content](fundamentals/design/rendering-content.md) - * [Rendering Media](fundamentals/design/rendering-media.md) - * [Partial Views](fundamentals/design/partial-views.md) - * [Partial View Macro Files](fundamentals/design/partial-view-macro-files.md) - * [Stylesheets And JavaScript](fundamentals/design/stylesheets-javascript.md) -* [Code](fundamentals/code/README.md) - * [Service APIs](fundamentals/code/umbraco-services.md) - * [Subscribing To Notifications](fundamentals/code/subscribing-to-notifications.md) - * [Creating Forms](fundamentals/code/creating-forms.md) - * [Debugging](fundamentals/code/debugging/README.md) - * [Logging](fundamentals/code/debugging/logging.md) - * [Source Control](fundamentals/code/source-control.md) - -## Implementation - -* [Learn how Umbraco works](implementation/learn-how-umbraco-works.md) -* [Routing](implementation/default-routing/README.md) - * [Controller & Action Selection](implementation/default-routing/controller-selection.md) - * [Execute Request](implementation/default-routing/execute-request.md) - * [Request Pipeline](implementation/default-routing/inbound-pipeline.md) -* [Custom Routing](implementation/custom-routing/README.md) - * [Adding a hub with SignalR and Umbraco](implementation/custom-routing/signalR.md) -* [Controllers](implementation/controllers.md) -* [Data Persistence (CRUD)](implementation/data-persistence.md) -* [Composing](implementation/composing.md) -* [Integration Testing](implementation/integration-testing.md) -* [Nullable Reference Types](implementation/nullable-reference-types.md) -* [Services and Helpers](implementation/services/README.md) - * [Circular Dependencies](implementation/services/circular-dependencies.md) -* [Unit Testing](implementation/unit-testing.md) - -## Extending - -* [Customize the editing experience](extending/customize-the-editing-experience.md) -* [Dashboards](extending/dashboards.md) -* [Sections & Trees](extending/section-trees/README.md) - * [Sections](extending/section-trees/sections.md) - * [Trees](extending/section-trees/trees/README.md) - * [Tree Actions](extending/section-trees/trees/tree-actions.md) - * [Searchable Trees (ISearchableTree)](extending/section-trees/searchable-trees.md) -* [Property Editors](extending/property-editors/README.md) - * [Package Manifest](extending/property-editors/package-manifest.md) - * [Property Value Converters](extending/property-editors/property-value-converters.md) - * [Property Actions](extending/property-editors/property-actions.md) - * [Tracking References](extending/property-editors/tracking.md) - * [Declaring your property editor](extending/property-editors/declaring-your-property-editor.md) - * [Content Picker Value Converter Example](extending/property-editors/full-examples-value-converters.md) -* [Macro Parameter Editors](extending/macro-parameter-editors.md) -* [Health Check](extending/health-check/README.md) - * [Health Check Guides](extending/health-check/guides/README.md) - * [Click-Jacking Protection](extending/health-check/guides/clickjackingprotection.md) - * [Content/MIME Sniffing Protection](extending/health-check/guides/contentsniffingprotection.md) - * [Cross-site scripting Protection (X-XSS-Protection header)](extending/health-check/guides/crosssitescriptingprotection.md) - * [Debug Compilation Mode](extending/health-check/guides/debugcompilationmode.md) - * [Excessive Headers](extending/health-check/guides/excessiveheaders.md) - * [Fixed Application Url](extending/health-check/guides/fixedapplicationurl.md) - * [Folder & File Permissions](extending/health-check/guides/folderandfilepermissions.md) - * [HTTPS Configuration](extending/health-check/guides/httpsconfiguration.md) - * [Macro Errors](extending/health-check/guides/macroerrors.md) - * [Notification Email Settings](extending/health-check/guides/notificationemail.md) - * [SMTP](extending/health-check/guides/smtp.md) - * [Strict-Transport-Security Header](extending/health-check/guides/stricttransportsecurityheader.md) -* [Language Files & Localization](extending/language-files.md) -* [Backoffice Search](extending/backoffice-search.md) -* [Backoffice Tours](extending/backoffice-tours.md) -* [Backoffice UI API Documentation](extending/backoffice-ui-api-documentation.md) -* [Content Apps](extending/content-apps.md) -* [Creating a Custom Database Table](extending/database.md) -* [Embedded Media Providers](extending/embedded-media-providers.md) -* [Custom File Systems (IFileSystem)](extending/filesystemproviders/README.md) - * [Using Azure Blob Storage for Media and ImageSharp Cache](extending/filesystemproviders/azure-blob-storage.md) -* [Configuring Azure Key Vault](extending/key-vault.md) -* [Packages](extending/packages/README.md) - * [Package Types](extending/packages/types-of-packages.md) - * [Creating a Package](extending/packages/creating-a-package.md) - * [Language file for packages](extending/packages/language-files-for-packages.md) - * [Listing a Package on the Umbraco Marketplace](extending/packages/listing-on-marketplace.md) - * [Good practice and defaults](extending/packages/good-practice-and-defaults.md) - * [Packages on Umbraco Cloud](extending/packages/packages-on-umbraco-cloud.md) - * [Installing and Uninstalling Packages](extending/packages/installing-and-uninstalling-packages.md) - * [Maintaining packages](extending/packages/maintaining-packages.md) - * [Create accessible Umbraco packages](extending/packages/accessibility.md) - * [Example Package Repository](extending/packages/example-package-repository.md) -* [UI Library](extending/ui-library.md) - -## Reference - -* [Dive into the code](reference/dive-into-the-code.md) -* [Configuration](reference/configuration/README.md) - * [Basic Authentication Settings](reference/configuration/basicauthsettings.md) - * [Connection strings settings](reference/configuration/connectionstringssettings.md) - * [Content Dashboard Settings](reference/configuration/contentdashboard.md) - * [Content Settings](reference/configuration/contentsettings.md) - * [Data Types Settings](reference/configuration/datatypes.md) - * [Debug settings](reference/configuration/debugsettings.md) - * [Examine settings](reference/configuration/examinesettings.md) - * [Exception filter settings](reference/configuration/exceptionfiltersettings.md) - * [FileSystemProviders Configuration](reference/configuration/filesystemproviders.md) - * [Global Settings](reference/configuration/globalsettings.md) - * [Health checks](reference/configuration/healthchecks.md) - * [Hosting settings](reference/configuration/hostingsettings.md) - * [Imaging settings](reference/configuration/imagingsettings.md) - * [Indexing settings](reference/configuration/indexingsettings.md) - * [Install Default Data Settings](reference/configuration/installdefaultdatasettings.md) - * [Keep alive settings](reference/configuration/keepalivesettings.md) - * [Logging settings](reference/configuration/loggingsettings.md) - * [Maximum Upload Size Settings](reference/configuration/maximumuploadsizesettings.md) - * [Models builder settings](reference/configuration/modelsbuildersettings.md) - * [NuCache Settings](reference/configuration/nucachesettings.md) - * [Package Migration](reference/configuration/packagemigrationsettings.md) - * [Plugins settings](reference/configuration/pluginssettings.md) - * [Request handler settings](reference/configuration/requesthandlersettings.md) - * [Rich text editor settings](reference/configuration/richtexteditorsettings.md) - * [Runtime minification settings](reference/configuration/runtimeminificationsettings.md) - * [Runtime settings](reference/configuration/runtimesettings.md) - * [Security Settings](reference/configuration/securitysettings.md) - * [Serilog settings](reference/configuration/serilog.md) - * [Tours settings](reference/configuration/tourssettings.md) - * [Type finder settings](reference/configuration/typefindersettings.md) - * [Unattended](reference/configuration/unattendedsettings.md) - * [Web routing](reference/configuration/webroutingsettings.md) -* [Templating](reference/templating/README.md) - * [Macros](reference/templating/macros/README.md) - * [Managing macros](reference/templating/macros/managing-macros.md) - * [Partial View Macros](reference/templating/macros/partial-view-macros.md) - * [Models Builder](reference/templating/modelsbuilder/README.md) - * [Introduction](reference/templating/modelsbuilder/introduction.md) - * [Configuration](reference/templating/modelsbuilder/configuration.md) - * [Builder Modes](reference/templating/modelsbuilder/builder-modes.md) - * [Understand and Extend](reference/templating/modelsbuilder/understand-and-extend.md) - * [Using Interfaces](reference/templating/modelsbuilder/using-interfaces.md) - * [Tips and Tricks](reference/templating/modelsbuilder/coolthingswithmodels.md) - * [Working with MVC](reference/templating/mvc/README.md) - * [Working with MVC Views in Umbraco](reference/templating/mvc/views.md) - * [View/Razor Examples](reference/templating/mvc/examples.md) - * [Using MVC Partial Views in Umbraco](reference/templating/mvc/partial-views.md) - * [Using View Components in Umbraco](reference/templating/mvc/viewcomponents.md) - * [Querying & Traversal](reference/templating/mvc/querying.md) - * [Creating Forms](reference/templating/mvc/forms.md) -* [Querying & Models](reference/querying/README.md) - * [IMemberManager](reference/querying/imembermanager.md) - * [IPublishedContentQuery](reference/querying/ipublishedcontentquery.md) - * [ITagQuery](reference/querying/itagquery.md) - * [UDI Identifiers](reference/querying/udi-identifiers.md) - * [UmbracoContext helper](reference/querying/umbraco-context.md) - * [UmbracoHelper](reference/querying/umbracohelper.md) - * [IPublishedContent](reference/querying/ipublishedcontent/README.md) - * [IPublishedContent Collections](reference/querying/ipublishedcontent/collections.md) - * [IPublishedContent IsHelpers](reference/querying/ipublishedcontent/ishelpers.md) - * [IPublishedContent Property Access & Extension Methods](reference/querying/ipublishedcontent/properties.md) -* [Routing & Controllers](reference/routing/README.md) - * [Routing requirements for backoffice authentication](reference/routing/authorized.md) - * [Custom MVC controllers (Umbraco Route Hijacking)](reference/routing/custom-controllers.md) - * [Custom MVC Routes](reference/routing/custom-routes.md) - * [URL Rewrites in Umbraco](reference/routing/iisrewriterules.md) - * [Special Property Type aliases for routing](reference/routing/routing-properties.md) - * [URL Redirect Management](reference/routing/url-tracking.md) - * [Routing in Umbraco](reference/routing/request-pipeline/README.md) - * [FindPublishedContentAndTemplate()](reference/routing/request-pipeline/find-publishedcontent-and-template.md) - * [IContentFinder](reference/routing/request-pipeline/icontentfinder.md) - * [Inbound request pipeline](reference/routing/request-pipeline/inbound-pipeline.md) - * [Outbound request pipeline](reference/routing/request-pipeline/outbound-pipeline.md) - * [Published Content Request Preparation](reference/routing/request-pipeline/published-content-request-preparation.md) - * [Surface controllers](reference/routing/surface-controllers/README.md) - * [Surface controller actions](reference/routing/surface-controllers/surface-controllers-actions.md) - * [Umbraco API Controllers](reference/routing/umbraco-api-controllers/README.md) - * [Umbraco Api - Authorization](reference/routing/umbraco-api-controllers/authorization.md) - * [Umbraco Api - Routing & Urls](reference/routing/umbraco-api-controllers/routing.md) -* [Searching](reference/searching/README.md) - * [Examine](reference/searching/examine/README.md) - * [Examine Management](reference/searching/examine/examine-management.md) - * [Examine Manager](reference/searching/examine/examine-manager.md) - * [Custom indexing](reference/searching/examine/indexing.md) - * [PDF indexes and multisearchers](reference/searching/examine/pdfindex-multisearcher.md) - * [quick-start](reference/searching/examine/quick-start.md) -* [Using Notifications](reference/notifications/README.md) - * [Notification Handler](reference/notifications/notification-handler.md) - * [CacheRefresher Notifications Example](reference/notifications/cacherefresher-notifications.md) - * [ContentService Notifications Example](reference/notifications/contentservice-notifications.md) - * [Creating And Publishing Notifications](reference/notifications/creating-and-publishing-notifications.md) - * [Determining if an entity is new](reference/notifications/determining-new-entity.md) - * [MediaService Notifications Example](reference/notifications/mediaservice-notifications.md) - * [MemberService Notifications Example](reference/notifications/memberservice-notifications.md) - * [Sending Allowed Children Notification](reference/notifications/sendingallowedchildrennotifications.md) - * [Umbraco Application Lifetime Notifications](reference/notifications/umbracoapplicationlifetime-notifications.md) - * [EditorModel Notifications](reference/notifications/editormodel-notifications/README.md) - * [Customizing the "Links" box](reference/notifications/editormodel-notifications/customizing-the-links-box.md) -* [Inversion of Control / Dependency injection](reference/using-ioc.md) -* [Management](reference/management/README.md) - * [Models Reference](reference/management/models/README.md) - * [Content](reference/management/models/content.md) - * [ContentType](reference/management/models/contenttype.md) - * [DataType](reference/management/models/datatype.md) - * [DictionaryItem](reference/management/models/dictionaryitem.md) - * [Language](reference/management/models/language.md) - * [Media](reference/management/models/media.md) - * [MediaType](reference/management/models/mediatype.md) - * [Relation](reference/management/models/relation.md) - * [RelationType](reference/management/models/relationtype.md) - * [ServerRegistration](reference/management/models/serverregistration.md) - * [Template](reference/management/models/template.md) - * [Services Reference](reference/management/services/README.md) - * [AuditService](reference/management/services/auditservice.md) - * [ConsentService](reference/management/services/consentservice.md) - * [DataTypeService](reference/management/services/datatypeservice.md) - * [DomainService](reference/management/services/domainservice.md) - * [EntityService](reference/management/services/entityservice.md) - * [ExternalLoginService](reference/management/services/externalloginservice.md) - * [FileService](reference/management/services/fileservice.md) - * [MacroService](reference/management/services/macroservice.md) - * [MediaService](reference/management/services/mediaservice.md) - * [MemberGroupService](reference/management/services/membergroupservice.md) - * [MemberService](reference/management/services/memberservice.md) - * [MemberTypeService](reference/management/services/membertypeservice.md) - * [NotificationService](reference/management/services/notificationservice.md) - * [PackagingService](reference/management/services/packagingservice.md) - * [PublicAccessService](reference/management/services/publicaccessservice.md) - * [RedirectUrlService](reference/management/services/redirecturlservice.md) - * [RelationService](reference/management/services/relationservice.md) - * [ServerRegistrationService](reference/management/services/serverregistrationservice.md) - * [TagService](reference/management/services/tagservice.md) - * [TextService](reference/management/services/textservice.md) - * [ContentService](reference/management/services/contentservice/README.md) - * [Create content programmatically](reference/management/services/contentservice/create-content-programmatically.md) - * [ContentTypeService](reference/management/services/contenttypeservice/README.md) - * [Retrieving content types](reference/management/services/contenttypeservice/retrieving-content-type-containers.md) - * [Retrieving content types](reference/management/services/contenttypeservice/retrieving-content-types.md) - * [LocalizationService](reference/management/services/localizationservice/README.md) - * [Retrieving languages](reference/management/services/localizationservice/retrieving-languages.md) - * [UserService](reference/management/services/userservice/README.md) - * [Creating a user](reference/management/services/userservice/create-a-new-user.md) -* [Plugins](reference/plugins/README.md) - * [Creating Resolvers](reference/plugins/creating-resolvers.md) - * [Finding types](reference/plugins/finding-types.md) -* [Cache & Distributed Cache](reference/cache/README.md) - * [Accessing the cache](reference/cache/application-cache.md) - * [ICacheRefresher](reference/cache/icacherefresher.md) - * [IServerMessenger](reference/cache/iservermessenger.md) - * [Getting/Adding/Updating/Inserting Into Cache](reference/cache/updating-cache.md) - * [Examples](reference/cache/examples/README.md) - * [Working with caching](reference/cache/examples/tags.md) -* [Response Caching](reference/response-caching.md) -* [Security](reference/security/README.md) - * [Linking External Login Provider accounts](reference/security/auto-linking.md) - * [BackOfficeUserManager and Events](reference/security/backofficeusermanager-and-notifications.md) - * [Cookies](reference/security/cookies.md) - * [Replacing the basic username/password check](reference/security/custom-password-check.md) - * [External login providers](reference/security/external-login-providers.md) - * [Locking of Users and password reset](reference/security/password-reset.md) - * [Reset admin password](reference/security/reset-admin-password.md) - * [Umbraco Security Hardening](reference/security/security-hardening.md) - * [Umbraco Security Settings](reference/security/security-settings.md) - * [Sensitive data](reference/security/sensitive-data-on-members.md) - * [Sanitizing the Rich Text Editor](reference/security/serverside-sanitizing.md) - * [Setup Umbraco for a FIPS Compliant Server](reference/security/setup-umbraco-for-a-fips-server.md) - * [HTTPS](reference/security/ssl-https.md) - * [Two-factor Authentication](reference/security/two-factor-authentication.md) - * [Server-side file validation](reference/security/serverside-file-validation.md) -* [Scheduling](reference/scheduling.md) -* [Common Pitfalls & Anti-Patterns](reference/common-pitfalls.md) -* [API Documentation](reference/api-documentation.md) -* [Debugging with SourceLink](reference/debugging.md) -* [Language Variation](reference/language-variation.md) -* [UmbracoMapper](reference/mapping.md) -* [Distributed Locks](reference/distributed-locks.md) -* [AngularJS](reference/angular/README.md) - * [Directives](reference/angular/directives/README.md) - * [umbLayoutSelector](reference/angular/directives/umblayoutselector.md) - * [umbLoadIndicator](reference/angular/directives/umbloadindicator.md) - * [umbProperty](reference/angular/directives/umbproperty.md) - * [Services](reference/angular/services/README.md) - * [Editor Service](reference/angular/services/editorservice.md) - * [Events Service](reference/angular/services/eventsservice/README.md) - * [changeTitle](reference/angular/services/eventsservice/changetitle.md) - -## Tutorials - -* [Overview](tutorials/overview.md) -* [Creating a Basic Website](tutorials/creating-a-basic-website/README.md) - * [Getting Started](tutorials/creating-a-basic-website/getting-started.md) - * [Document Types](tutorials/creating-a-basic-website/document-types.md) - * [Creating Your First Template](tutorials/creating-a-basic-website/creating-your-first-template-and-content-node.md) - * [CSS and Images](tutorials/creating-a-basic-website/css-and-images.md) - * [Displaying the Document Type Properties](tutorials/creating-a-basic-website/displaying-the-document-type-properties.md) - * [Creating a Master Template](tutorials/creating-a-basic-website/creating-master-template-part-1.md) - * [Creating Pages and Using the Master Template](tutorials/creating-a-basic-website/creating-master-template-part-2.md) - * [Setting the Navigation Menu](tutorials/creating-a-basic-website/setting-the-navigation-menu.md) - * [Articles and Article Items](tutorials/creating-a-basic-website/article-parent-and-article-items.md) - * [Adding Language Variants](tutorials/creating-a-basic-website/adding-language-variants.md) - * [Conclusions](tutorials/creating-a-basic-website/conclusion.md) -* [Creating a Custom Dashboard](tutorials/creating-a-custom-dashboard.md) -* [Creating a Property Editor](tutorials/creating-a-property-editor/README.md) - * [Adding configuration to a property editor](tutorials/creating-a-property-editor/part-2.md) - * [Integrating services with a property editor](tutorials/creating-a-property-editor/part-3.md) - * [Adding server-side data to a property editor](tutorials/creating-a-property-editor/part-4.md) -* [Creating a Multilingual Site](tutorials/multilanguage-setup.md) -* [Add Google Authentication](tutorials/add-google-authentication.md) -* [Add Microsoft Entra ID authentication (Members)](tutorials/add-microsoft-entra-id-authentication.md) -* [The Starter Kit](tutorials/starter-kit/README.md) - * [Install the Starter Kit](tutorials/starter-kit/install-the-starter-kit.md) - * [Lessons](tutorials/starter-kit/lessons/README.md) - * [Customize the Starter Kit](tutorials/starter-kit/lessons/1-customize-the-starter-kit.md) - * [Add a Blog Post Publication Date](tutorials/starter-kit/lessons/2-add-a-blog-post-publication-date/README.md) - * [Add a Blog Post Publication Date](tutorials/starter-kit/lessons/2-add-a-blog-post-publication-date/part-2.md) - * [Add a Blog Post Publication Date](tutorials/starter-kit/lessons/2-add-a-blog-post-publication-date/part-3.md) - * [Add Open Graph](tutorials/starter-kit/lessons/3-add-open-graph/README.md) - * [Add Open Graph - Step 1](tutorials/starter-kit/lessons/3-add-open-graph/step-1.md) - * [Add Open Graph - Step 2](tutorials/starter-kit/lessons/3-add-open-graph/step-2.md) - * [Add Open Graph - Step 3](tutorials/starter-kit/lessons/3-add-open-graph/step-3.md) - * [Add Open Graph - Step 4](tutorials/starter-kit/lessons/3-add-open-graph/step-4.md) - * [Add Open Graph - Summary](tutorials/starter-kit/lessons/3-add-open-graph/summary.md) - * [Ask For Help and Join the Community](tutorials/starter-kit/lessons/4-help-and-community.md) -* [Editor's Manual](tutorials/editors-manual/README.md) - * [Getting Started](tutorials/editors-manual/getting-started-with-umbraco/README.md) - * [Logging In and Out](tutorials/editors-manual/getting-started-with-umbraco/logging-in-and-out.md) - * [Umbraco Interface](tutorials/editors-manual/getting-started-with-umbraco/umbraco-interface.md) - * [Creating, Saving and Publishing Content Options](tutorials/editors-manual/getting-started-with-umbraco/creating-saving-and-publishing-content.md) - * [Finding Content](tutorials/editors-manual/getting-started-with-umbraco/finding-content.md) - * [Editing Existing Content](tutorials/editors-manual/getting-started-with-umbraco/editing-existing-content.md) - * [Sorting Pages](tutorials/editors-manual/getting-started-with-umbraco/ordering-pages.md) - * [Moving a Page](tutorials/editors-manual/getting-started-with-umbraco/moving-a-page.md) - * [Copying a Page](tutorials/editors-manual/getting-started-with-umbraco/copying-a-page.md) - * [Deleting and Restoring Pages](tutorials/editors-manual/getting-started-with-umbraco/deleting-and-restoring-pages.md) - * [Working with Rich Text Editor](tutorials/editors-manual/working-with-content/README.md) - * [Version Management](tutorials/editors-manual/version-management/README.md) - * [Comparing Versions](tutorials/editors-manual/version-management/comparing-versions.md) - * [Rollback to a Previous Version](tutorials/editors-manual/version-management/rollback-to-a-previous-version.md) - * [Media Management](tutorials/editors-manual/media-management/README.md) - * [Working with Folders](tutorials/editors-manual/media-management/working-with-folders.md) - * [Working with Media Types](tutorials/editors-manual/media-management/working-with-images-and-files.md) - * [Cropping Images](tutorials/editors-manual/media-management/cropping-images.md) - * [Tips & Tricks](tutorials/editors-manual/tips-and-tricks/README.md) - * [Refreshing the Tree View](tutorials/editors-manual/tips-and-tricks/working-with-folders.md) - * [Audit Trail](tutorials/editors-manual/tips-and-tricks/audit-trail.md) - * [Notifications](tutorials/editors-manual/tips-and-tricks/notifications.md) - * [Preview Pane Responsive View](tutorials/editors-manual/tips-and-tricks/preview-pane-responsive-view.md) - * [Session Timeout](tutorials/editors-manual/tips-and-tricks/session-timeout.md) -* [Multisite Setup](tutorials/multisite-setup.md) -* [Member Registration and Login](tutorials/members-registration-and-login.md) -* [Custom Views for Block List](tutorials/creating-custom-views-for-blocklist.md) -* [Connecting Umbraco Forms and Zapier](tutorials/connecting-umbraco-forms-and-zapier.md) -* [Creating an XML Sitemap](tutorials/creating-an-xml-site-map.md) -* [Implementing Custom Error Pages](tutorials/custom-error-page.md) diff --git a/10/umbraco-cms/extending/backoffice-search.md b/10/umbraco-cms/extending/backoffice-search.md deleted file mode 100644 index 732dcda4c8a..00000000000 --- a/10/umbraco-cms/extending/backoffice-search.md +++ /dev/null @@ -1,103 +0,0 @@ ---- - - -meta.Title: "Backoffice Search" -description: "A guide to customization of Backoffice Search" ---- - -# Backoffice Search - -The search facility of the Umbraco Backoffice allows the searching 'across sections' of different types of Umbraco entities, for example Content, Media, Members. However 'by default' only a small subset of standard fields are searched: - -| Node Type | Propagated Fields | -| ------------ | ---------------------- | -| All Nodes | Id, _NodeId_ and _Key_ | -| Media Nodes | UmbracoFileFieldName | -| Member Nodes | email, loginName | - -An Umbraco implementation might have additional custom properties that it would be useful to include in a Backoffice Search. For example: an 'Organisation Name' property on a Member Type, or a 'Product Code' field for a 'Product' content item. - -## Adding custom properties to backoffice search - -To add custom properties, it is required to register a custom implementation of `IUmbracoTreeSearcherFields`. We recommend to override the existing `UmbracoTreeSearcherFields`. - -Your custom implementation needs to be registered in the container. For example in the `Startup.ConfigureServices` method or in a composer, as an alternative. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - ... - - services.AddUnique(); -} -``` - -or - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Infrastructure.Examine; -using Umbraco.Extensions; - -namespace Umbraco.Docs.Samples.Web.BackofficeSearch -{ - public class BackofficeSearchComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - } - } -} -``` - -```csharp -using System.Collections.Generic; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Examine; -using Umbraco.Cms.Infrastructure.Search; - -namespace Umbraco.Docs.Samples.Web.BackofficeSearch -{ - public class CustomUmbracoTreeSearcherFields : UmbracoTreeSearcherFields, IUmbracoTreeSearcherFields - { - public CustomUmbracoTreeSearcherFields(ILocalizationService localizationService) : base(localizationService) - { - } - - //Adding custom field to search in all nodes - public new IEnumerable GetBackOfficeFields() - { - return new List(base.GetBackOfficeFields()) { "nodeType" }; - } - - //Adding custom field to search in document types - public new IEnumerable GetBackOfficeDocumentFields() - { - return new List(base.GetBackOfficeDocumentFields()) { "nodeType" }; - } - - //Adding custom field to search in media - public new IEnumerable GetBackOfficeMediaFields() - { - return new List(base.GetBackOfficeMediaFields()) { "nodeType" }; - } - - //Adding custom field to search in members - public new IEnumerable GetBackOfficeMembersFields() - { - return new List(base.GetBackOfficeMembersFields()) { "nodeType" }; - } - } -} -``` - -{% hint style="warning" %} -You cannot use this to search on integer types in the index, as an example `parentID` does not work. -{% endhint %} - -## More advanced extensions - -For further extensibility of the Umbraco Backoffice search implementation check [ISearchableTree](section-trees/searchable-trees.md) diff --git a/10/umbraco-cms/extending/backoffice-tours.md b/10/umbraco-cms/extending/backoffice-tours.md deleted file mode 100644 index e9ec546e194..00000000000 --- a/10/umbraco-cms/extending/backoffice-tours.md +++ /dev/null @@ -1,230 +0,0 @@ ---- -meta.Title: Backoffice Tours -description: A guide configuring backoffice tours in Umbraco ---- - -# Backoffice Tours - -Backoffice Tours are a way to create helpful guides for how to work in the Umbraco backoffice. - -They are managed in a JSON format and stored in files on disk. The filenames should end with the `.json` extension. - -## Tour File Locations - -The tour functionality will load information from multiple locations. - -* **Core tours** - - The tour that ship with Umbraco are embedded into the CMS assemblies. -* **Custom tours** - - Custom tours need to be added as custom plugin/package. The custom json tour file needs to be added in `/App_Plugins//backoffice/tours`. The custom tours can be added independently, or [as part of a plugin/package](packages/creating-a-package.md). - -## The JSON Format - -A tour file contains an array of tour configuration JSON objects. It's possible to have multiple, (un)related tours in one file. - -```json -[ - { - // tour configuration object - }, - { - // tour configuration object - } -] -``` - -## The Tour Configuration Object - -A tour configuration JSON object contains all the data related to a tour. - -Example tour configuration object: - -```json -[ - { - "name": "My Custom Backoffice tour", - "alias": "myCustomBackofficeTour", - "group": "Get things done!!!", - "groupOrder": 1, - "allowDisable": true, - "culture": "en-US", - "contentType": "", - "requiredSections": [ "content", "media" ], - "steps": [] - } -] -``` - -Below is an explanation of each of the properties on the tour configuration object: - -* **name** - - This is the name that is displayed in the help drawer for the tour. - - ![Tour name highlighted](images/tourname-v8.png) -* **alias** - - The unique alias of your tour. This is used to track the progress a user has made while taking a tour. The progress information is stored in the `TourData` column of the `UmbracoUsers` table in the database. -* **group** - - The group property is used to group related tours in the help drawer under a common subject (for example Getting started). - - ![Tour group highlighted](images/tourgroup-v8.png) -* **groupOrder** - - This is used to control the order of the groups in the help drawer. This must be an integer value. -* **allowDisable** - - A boolean value that indicates if the "Don't show this tour again" should be shown on the tour steps. If the user clicks this link the tour will no longer be shown in the help drawer. - - ![Tour allow disable link highlighted](images/tourallowdisable-v8.png) -* **culture** - - You have the option to set a culture, such as nl-NL. This tour will exclusively be displayed to users who have set this culture in their profile. -* **contentType** - - Use this property if you want to limit the tour to a specific content type. To create a tour for content nodes using the Home Page, set the `contentType` property with the alias `homePage`. - - The `contentType` property can also be used to limit the tours to content types that are using a specific composition. This will show the tour on all nodes that are using a specific composition. - - ![Content Type specific tours]() - - In the image above, two tours are available on the _Welcome_ node: - - 1. "Setup the Welcome page" is available because the tour is limited to the `homePage` content type and - 2. "Setup the Search Engine Optimization (SEO)" is available because the content type uses the `SEO` composition, which is associated with a specific tour. - - When the `contentType` property is set, the tour will **not** show as part of any groups. -* **requiredSections** - - This is an array of section aliases that a user needs to have access to in order to see the tour. If the user does not have access to all the sections the tour will not be shown in the help drawer. For example if a user lacks access to Settings but has access to Content and Media, the tour requiring all three will not be shown. -* **steps** - - This is an array of tour step JSON objects that a user needs to take to complete the tour. - -## The Tour Step Object - -A tour step JSON object contains all the data related to a tour step. - -Example tour step object: - -```json -"steps": [ - { - "title": "A meaningful title", - "content": "

Some text explaining the step

", - "type": null, - "element": "[data-element='global-user']", - "elementPreventClick": false, - "backdropOpacity": 0.6, - "event": "click", - "view": null, - "eventElement": "[data-element='global-user'] .umb-avatar", - "skipStepIfVisible": ".css-element-selector", - "customProperties": null - } - ] -``` - -Below is an explanation of each of the properties on the tour step object. - -* **title** - - This the title shown on the tour step. - - ![Tour step highlighted](images/steptitle-v8.png) -* **content** - - This text will be shown on the tour step, it can contain HTML markup. - - ![Tour content highlighted](images/stepcontent-v8.png) -* **type** - - The type of step. Currently, only one type is supported : "intro". This will center the step and show a "Start tour" button. -* **element** - - A CSS selector for the element you wish to highlight. The tour step will position itself near the element. - - A lot of elements in the Umbraco backoffice have a "data-element" attribute. It's recommended to use that, because "id" and "class" are subject to changes, e.g.: - - ```xml - [data-element='section-content'] - ``` - - {% hint style="info" %} - Use the developer tools from your browser to find the id, class and data-attribute. - {% endhint %} - -
- -* **elementPreventClick** - - Setting this to true will prevent JavaScript events from being bound to the highlighted element. A "Next" button will be added to the tour step. - - As an example, it is useful when you would like to highlight a button, but would like to prevent the user clicking it. -* **backdropOpacity** - - A decimal value between 0 and 1 to indicate the transparency of the background overlay. -* **event** - - The JavaScript event that is bound to the highlighted element that should trigger the next tour step for example click, hover, etc. - - If not set or omitted a "Next" button will be added to the tour. -* **view** - - Here you can enter a path to your own custom AngularJS view that will be used to display the tour step. - - This is useful if you would like to validate input from the user during the tour step. -* **eventElement** - - A CSS selector for the element you wish to attach the JavaScript event. Highlighting a larger section of the backoffice while encouraging users to click on a specific element can be useful.. If not set, the selector in the element property will be used. - - The image below shows the entire tree highlighted, but requires the user to click on a specific tree element. - - ![Step eventElement highlighted](images/step-event-element-v8.png) -* **skipStepIfVisible** - - A CSS selector for an element that, if it is visible, will skip this tour step. - - This is useful for excluding a navigational step if the user is already there. Or skipping a step that would toggle an eventElement to the wrong state. -* **customProperties** - - A JSON object that is passed to the scope of a custom step view, so you can use this data in your view with `$scope.model.currentStep.customProperties`. - -## How to Filter/Disable Tours from being shown - -It is possible to hide/disable tours using a C# composer by adding to the TourFilters collection. - -Here is an example of disabling all the CMS core tours based on the alias. Additionally, we provide examples of filtering tours by JSON filename and disabling tours from specific packages. - -``` -using System.Text.RegularExpressions; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Tour; - -namespace Umbraco.Docs.Samples.Web.BackofficeTours -{ - public class BackofficeComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Filter out all the CMS core tours by alias with a Regex that start with the umbIntro alias - builder.TourFilters() - .AddFilter(new BackOfficeTourFilter(pluginName: null, tourFileName: null, tourAlias: new Regex("^umbIntro", RegexOptions.IgnoreCase))); - - // Filter any tours in the file that is custom-tours.json - // Found in App_Plugins/MyCustomBackofficeTour/backoffice/tours/ - builder.TourFilters() - .AddFilterByFile("custom-tours"); //Without extension - - // Filter out one or more tour JSON files from a specific plugin/package - // Found in App_Plugins/MyCustomBackofficeTour/backoffice/tours/custom-tours.json - builder.TourFilters() - .AddFilterByPlugin("MyCustomBackofficeTour"); - } - } -} -``` diff --git a/10/umbraco-cms/extending/backoffice-ui-api-documentation.md b/10/umbraco-cms/extending/backoffice-ui-api-documentation.md deleted file mode 100644 index c65f10255a4..00000000000 --- a/10/umbraco-cms/extending/backoffice-ui-api-documentation.md +++ /dev/null @@ -1,35 +0,0 @@ ---- - ---- - -# Backoffice UI API Documentation - -A library of API Reference documentation is auto-generated from the comments within the Umbraco Source Code. - -{% hint style="info" %} -A new backoffice for Umbraco CMS is currently being worked upon. It is planned to release with Umbraco version 14 in May 2024. - -We have gathered all information and resources about the project in one place, giving you a full overview of what we're working on. You will also be able to find information about how to get involved in the project. - -You can find it all on [docs.umbraco.com/umbraco-backoffice](https://docs.umbraco.com/umbraco-backoffice). -{% endhint %} - -## [Backoffice UI](https://apidocs.umbraco.com/v10/ui) - -Angular, JavaScript, CSS & Less UI API references for building Umbraco backoffice components. V10 is using minified versions of the following files: - -* The umbraco.directives -* The umbraco.services -* The umbraco.resources - -{% hint style="info" %} -Opens a documentation browser that is different from the documentation section you're viewing now. -{% endhint %} - -## [UI Examples](https://our.umbraco.com/packages/developer-tools/ui-examples/) - -There is a package available called 'UI Examples'. This package adds a new 'UI Examples' section to your Umbraco instance with working examples of how to customise the backoffice. - -{% hint style="info" %} -Opens a documentation browser that is different from the documentation section you're viewing now. -{% endhint %} diff --git a/10/umbraco-cms/extending/content-apps.md b/10/umbraco-cms/extending/content-apps.md deleted file mode 100644 index aceed80cda5..00000000000 --- a/10/umbraco-cms/extending/content-apps.md +++ /dev/null @@ -1,356 +0,0 @@ ---- -versionFrom: 9.2.0 -meta.Title: Content Apps -description: A guide configuring content apps in Umbraco ---- - -# Content Apps - -## What are Content Apps - -Content Apps are **companions** to the editing experience when working with content or media in the Umbraco backoffice. - -With Content Apps, editors can switch from editing 'Content' to accessing contextual information related to the item they are editing. - -![Content Apps in backoffice](images/content-app-1.png) - -### Default Content Apps - -**'Info'** - The 'Info' Content App is a default Content App for all items, displaying Links, History and Status of the current content item. - -### Custom Content Apps - -As an integrated part of Umbraco it is possible for you as a developer to create and provide your editors with helpful Content Apps. - -For example, you could create a Google Analytics integration within a Content App. This would then display to editors the current 'page views' for the content item they are editing. - -#### Controlling Appearance/Position - -You can associate an icon and control the position of your custom Content App. The position, for example between 'Content' and 'Info', is set via a 'weighting' number. - -#### Permissions - -Content Apps can be configured to appear dependent on Section, Content Type and User Group Permissions. - -#### Read-Only - -Content Apps are designed to be companions to the Content Item. They should enhance the editor's experience by enabling quick access to contextual information for the particular content item they are editing. Content Apps are not intended to be used for the editing content. - -## Creating a Custom Content App - -This guide explains how to set up a custom Content App in the following steps: - -* Adding a Content App that counts how many words are added for each property type -* Limiting the Content App to appear for only specific content types -* Limiting which user groups can see the Content App - -A basic understanding of how to use AngularJS with Umbraco is required. If you have created a property value editor before, this will all feel familiar. - -### Setting up the Plugin - -The first thing we do is create a new folder inside `/App_Plugins` folder. We will call it `WordCounter`. - -Next we need to create a manifest file to describe what this Content App does. This manifest will tell Umbraco about our new Content App and allows us to inject any needed files into the application. - -Create a new file in the `/App_Plugins/WordCounter/` folder and name it `package.manifest`. In this new file, copy the code snippet below and save it. This code describes the Content App. To help you understand the JSON, read the inline comments for details on each bit: - -```json5 -{ - // define the content apps you want to create - "contentApps": [ - { - "name": "Word Counter", // required - the name that appears under the icon - "alias": "wordCounter", // required - unique alias for your app - "weight": 0, // optional, default is 0, use values between -99 and +99 to appear between the existing Content (-100) and Info (100) apps - "icon": "icon-calculator", // required - the icon to use - "view": "~/App_Plugins/WordCounter/wordcounter.html", // required - the location of the view file - "show": [ - "+content/*" // show app for all content types - ] - } - ], - // array of files we want to inject into the application on app_start - "javascript": [ - "~/App_Plugins/WordCounter/wordcounter.controller.js" - ] -} -``` - -{% hint style="info" %} -Umbraco backoffice uses the Helveticons icon pack by default. -{% endhint %} - -### Creating the View and the Controller - -Add 2 additional files to the `/App_Plugins/WordCounter/` folder: - -* `wordcounter.html` -* `wordcounter.controller.js` - -These 2 files will be our main files for the app, with the `.html` file handling the view and the `.js` file handling the functionality. - -In the `.js` file we declare our AngularJS controller and inject Umbraco's editorState and userService: - -```javascript -angular.module("umbraco") - .controller("My.WordCounterApp", function ($scope, editorState, userService, contentResource) { - - var vm = this; - vm.CurrentNodeId = editorState.current.id; - vm.CurrentNodeAlias = editorState.current.contentTypeAlias; - - var counter = contentResource.getById(vm.CurrentNodeId).then(function (node) { - var properties = node.variants[0].tabs[0].properties; - - vm.propertyWordCount = {}; - - var index; - for (index = 0; index < properties.length; ++index) { - var words = properties[index].value; - var wordCount = words.trim().split(/\s+/).length; - - vm.propertyWordCount[properties[index].label] = wordCount; - } - }); - - var user = userService.getCurrentUser().then(function (user) { - vm.UserName = user.name; - }); - - }); -``` - -And in the `.html` file: - -```csharp -
- - - -
-

Property: {{key}}, amount of words: {{value}}

-
-
- -
    -
  • Current node id: {{vm.CurrentNodeId}}
  • -
  • Current node alias: {{vm.CurrentNodeAlias}}
  • -
  • Current user: {{vm.UserName}}
  • -
-
-
-
-``` - -### Checking it works - -After the above edits are done, restart your application. Go to any content node and you should now see an app called Word Counter. Clicking on the icon should say "Amount of words for each property" and confirm the details of the current item and user. You can now adapt your Content App to retrieve external data using the standard Umbraco and AngularJS approach. - -![Content App in action: Word Counter](images/content-app-2.png) - -### Limiting according to type - -You can set your Content App to only show for specific types by adding a 'show' directive in the `package.manifest` file. - -This can be done for both **Content/Media Types**, for **Member types** and for **Content Types** (Document Types) in the Settings section. - -Here is an example where all types are taken intro consideration when limiting access to a Content App: - -```json5 -{ - "contentApps": [ - { - "show": [ - "-content/homePage", // hide for content using the 'homePage' Document Type (Content section) - "+content/*", // show for content using any other Document Type (Content section) - "+media/*", // show for all Media Types - "-member/premiumMembers", // hide for Member Type 'premiumMembers' - "+member/*", // show for all other Member Types - "-contentType/textPage", // hide on the Document Type with alias 'textPage' (Settings section) - "+contentType/*", // show on all other Document Types (Settings section) - ] - } - ] -} -``` - -{% hint style="info" %} -When the 'show' directive is omitted then the app will be shown for all types. - -Also, when you want to exclude any type, make sure to include all the rest of that type, using `"+content/*"`, `"+media/*"` or `"+member/*"`. - -In this case the WordCounter app is only usable within the Content section so you have to exclude from all other types. -{% endhint %} - -### Limiting according to User Role - -In a similar way, you can limit your Content App according to user roles (groups). For example: - -```json5 -{ - "contentApps": [ - { - "show": [ - "+role/admin" // show for 'admin' user group - ] - } - ] -} -``` - -{% hint style="info" %} -When a role restriction is given in the manifest, it overrides any other restrictions based on type. -{% endhint %} - -## C#: Creating a Content App - -This is an example of how to create a Content App with C# and perform your own custom logic to show a Content App. Create a `WordCounter.cs` file with the following implementation: - -```csharp -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.ContentEditing; -using Umbraco.Cms.Core.Models.Membership; - -namespace My.Website -{ - public class WordCounterAppComponent : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Add our word counter content app into the composition aka into the DI - builder.ContentApps().Append(); - } - } - - public class WordCounterApp : IContentAppFactory - { - public ContentApp? GetContentAppFor(object source, IEnumerable userGroups) - { - // Can implement some logic with userGroups if needed - // Allowing us to display the content app with some restrictions for certain groups - if (userGroups.All(x => x.Alias.ToLowerInvariant() != Umbraco.Cms.Core.Constants.Security.AdminGroupAlias)) - return null; - - // Only show app on content items - if (!(source is IContent)) - return null; - - var content = ((IContent)source); - - // Only show app on content items with template - if (content.TemplateId is null) - return null; - - // Only show app on content with certain content type alias - // if (!content.ContentType.Alias.Equals("aliasName")) - // return null; - - return new ContentApp - { - Alias = "wordCounter", - Name = "Word Counter", - Icon = "icon-calculator", - View = "/App_Plugins/WordCounter/wordcounter.html", - Weight = 0 - }; - } - } -} -``` - -You will still need to add all of the files you added above. However, because your C# code is adding the Content App, the `package.manifest` file can be simplified like this: - -```json5 -{ - // array of files we want to inject into the application on app_start - "javascript": [ - "~/App_Plugins/WordCounter/wordcounter.controller.js" - ] -} -``` - -{% hint style="info" %} -You can also have a coloured icon for your Content App by specifying the icon in the format `icon-[name of icon] color-[name of color]`. For eg, an indigo colored icon can be specified for your Content App by specifying the icon as `"icon-calculator color-indigo"` in your Content App C# class or _package.manifest_ . -{% endhint %} - -## Notification badges - -There are times when you want to draw the attention of editors to your content badge, so they know they need to take some action. That is where notification badges come in to play. - -When you set a badge, a circle with a chosen background and a number in it will be added to the content app icon. - -![Content App badge](images/content-app-badge.png) - -You can enable a badge by using this code in the angular controller of your content app. - -```javascript -$scope.model.badge = { - count: 5, // the number for the badge - anything non-zero triggers the badge - type: "warning" // optional: determines the badge color - "warning" = dark yellow, "alert" = red, anything else = blue (matching the top-menu background color) -}; -``` - -Further customization can be done by setting a notification badge from an `IContentAppFactory`. This is achieved by setting the badge property on the ContentApp model. - -```csharp -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.ContentEditing; -using Umbraco.Cms.Core.Models.Membership; - -namespace My.Website -{ - public class WordCounterAppComponent : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Add our word counter content app into the composition aka into the DI - builder.ContentApps().Append(); - } - } - - public class WordCounterApp : IContentAppFactory - { - public ContentApp GetContentAppFor(object source, IEnumerable userGroups) - { - // Can implement some logic with userGroups if needed - // Allowing us to display the content app with some restrictions for certain groups - if (userGroups.All(x => x.Alias.ToLowerInvariant() != Umbraco.Cms.Core.Constants.Security.AdminGroupAlias)) - return null; - - // Only show app on content items - if (!(source is IContent)) - return null; - - var content = ((IContent)source); - - // Only show app on content items with template - if (content.TemplateId is null) - return null; - - // Only show app on content with certain content type alias - // if (!content.ContentType.Alias.Equals("aliasName")) - // return null; - - return new ContentApp - { - Alias = "wordCounter", - Name = "Word Counter", - Icon = "icon-calculator", - View = "/App_Plugins/WordCounter/wordcounter.html", - Weight = 0, - Badge = new ContentAppBadge { Count = 5 , Type = ContentAppBadgeType.Warning } - }; - } - } -} -``` - -Possible values for the `ContentAppBadge` Type are _Default_, _Alert_ and _Warning_. diff --git a/10/umbraco-cms/extending/customize-the-editing-experience.md b/10/umbraco-cms/extending/customize-the-editing-experience.md deleted file mode 100644 index d8461cfb254..00000000000 --- a/10/umbraco-cms/extending/customize-the-editing-experience.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -description: >- - Get an overview of the different options for extending and customizing the - Umbraco CMS backoffice. ---- - -# Customize the editing experience - -The backoffice is one of the main forces of Umbraco CMS. It is where you build the foundations for the website and where your content editors will work with the content. - -In this section, you will find all the resources you need to build an intuitive and fluid editor experience for your content editors. - -
DashboardsThe dashboard is where all the main functionality of the backoffice will be.dashboards.mddashboards-image.png
Sections and TreesExtend the backoffice by customizing existing and building new sections and trees.section-treestrees.image.png
Property EditorsLearn how to extend and build some of the main building blocks in Umbraco CMS.property-editorsproperty-image.png
Health ChecksLearn about the health checks that you can run on your site to verify its state.health-checkhealthchecks-image.png
Backoffice UI APIFamiliarize yourself with the Backoffice UI API to start extending the backoffice.backoffice-ui-api-documentation.mdbackoffice-ui-images.png
PackagesAdd your custom code into packages and distribute them to the rest of the Umbraco users.packagespackages-image.png
- -## Other ways to extend the Umbraco CMS backoffice - -* [Backoffice Tours](backoffice-tours.md) -* [Backoffice Search](backoffice-search.md) -* [Content Apps](content-apps.md) -* [Language files and localization](language-files.md) -* [Macro Parameter editors](macro-parameter-editors.md) - -## Also in this section - -{% content-ref url="database.md" %} -[database.md](database.md) -{% endcontent-ref %} - -{% content-ref url="key-vault.md" %} -[key-vault.md](key-vault.md) -{% endcontent-ref %} - -{% content-ref url="filesystemproviders/" %} -[filesystemproviders](filesystemproviders/) -{% endcontent-ref %} diff --git a/10/umbraco-cms/extending/dashboards.md b/10/umbraco-cms/extending/dashboards.md deleted file mode 100644 index 9d98cd0d445..00000000000 --- a/10/umbraco-cms/extending/dashboards.md +++ /dev/null @@ -1,340 +0,0 @@ ---- - - -meta.Title: "Umbraco Custom Dashboards" -description: "A guide to creating custom dashboards in Umbraco" ---- - -# Dashboards - -Each section of the Umbraco backoffice has its own set of default dashboards. - -The dashboard area of Umbraco is used to display an 'editor' for the selected item in the tree. If no item is selected, for example when the section is first loaded in the browser, then the default set of section dashboards are displayed in the dashboard area, arranged over multiple tabs. - -## Registering your Dashboard - -There are two approaches to registering a custom dashboard to appear in the Umbraco Backoffice: - -### Registering with the package.manifest file - -Add a file named 'package.manifest' to the 'App_Plugins' folder, containing the following JSON configuration pointing to your dashboard view: - -```json -{ - "dashboards": [ - { - "alias": "myCustomDashboard", - "view": "/App_Plugins/MyCustomDashboard/dashboard.html", - "sections": [ "content", "member", "settings" ], - "weight": -10 - } - ] -} -``` - -The section aliases can be found in the C# developer reference for [Umbraco.Cms.Core.Constants.Applications](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Constants.Applications.html). - -### Registering with C# Type - -By creating a C# class that implements `IDashboard` from `Umbraco.Cms.Core.Dashboards` then this will automatically be discovered by Umbraco at application startup time. - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Dashboards; -using Umbraco.Cms.Core; - -namespace Umbraco.Docs.Samples.Web.Dashboards -{ - [Weight(-10)] - public class MyCustomDashboard : IDashboard - { - public string Alias => "myCustomDashboard"; - - public string[] Sections => new[] - { - Constants.Applications.Content, - Constants.Applications.Members, - Constants.Applications.Settings - }; - - public string View => "/App_Plugins/MyCustomDashboard/dashboard.html"; - - public IAccessRule[] AccessRules => Array.Empty(); - - } -} -``` - -### Re-ordering / weighting - -Each dashboard regardless of how it is registered (package.manifest or C# or default core dashboard) uses a *weight* property to assign the order that the dashboard should be displayed. The dashboard with the lowest weighting number will be displayed first in a collection where one or more dashboards are visible for a section/application. - -For reference, here is a list of the weighting values for the default Umbraco dashboards, so you can assign a weighting to your custom dashboard with a higher or lower value to suit your custom ordering needs. - -**Content** - - - - - - - - - - - - - - - - - - - - - - - -
NameWeightLanguage KeyC# Type
Getting Started10dashboardTabs/contentIntroUmbraco.Cms.Core.Dashboards.ContentDashboard
Redirect URL Management20dashboardTabs/contentRedirectManagerUmbraco.Cms.Core.Dashboards.RedirectUrlDashboard
- -**Media** - - - - - - - - - - - - - - - - - -
NameWeightLanguage KeyC# Type
Content10dashboardTabs/mediaFolderBrowserUmbraco.Cms.Core.Dashboards.MediaDashboard
- -**Settings** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameWeightLanguage KeyC# Type
Welcome10dashboardTabs/settingsWelcomeUmbraco.Cms.Core.Dashboards.SettingsDashboard
Examine Management20dashboardTabs/settingsExamineUmbraco.Cms.Core.Dashboards.ExamineDashboard
Published Status30dashboardTabs/settingsPublishedStatusUmbraco.Cms.Core.Dashboards.PublishedStatusDashboard
Models Builder40dashboardTabs/settingsModelsBuilderUmbraco.Cms.Core.Dashboards.ModelsBuilderDashboard
Health Check50dashboardTabs/settingsHealthCheckUmbraco.Cms.Core.Dashboards.HealthCheckDashboard
- -**Members** - - - - - - - - - - - - - - - - - -
NameWeightLanguage KeyC# Type
Getting Started10dashboardTabs/memberIntroUmbraco.Cms.Core.Dashboards.MembersDashboard
- -**Forms** - - - - - - - - - - - - - - - - - -
NameWeightLanguage KeyC# Type
Install Umbraco Forms10dashboardTabs/formsInstallUmbraco.Cms.Core.Dashboards.FormsDashboard
- -### Add Language Keys - -After registering your dashboard, it will appear in the backoffice - however, it will have its dashboard alias [mycustomdashboard] wrapped in square brackets. This is because it is missing a language key. The language key allows people to provide a translation of the dashboard name in multilingual environments. To remove the square brackets - add a language key: - -If your dashboard is unique to your installation, you can add or modify the relevant language files: `config/lang/{language}.user.xml` (e.g. `config/lang/en-US.user.xml`). If the dashboard is to be released as an Umbraco package, you will need to create a *lang* folder in your custom dashboard folder. You also need to create a package-specific language file: `App_Plugins/Mycustomdashboard/lang/en-US.xml`. - -[Read more about language files](language-files.md) - -```xml - - - - My Dashboard - - -``` - -### Specifying permissions - -You can configure which applications/sections a dashboard will appear in, in the above examples (package.manifest or C#), you can see the alias of the section is used to control where the dashboard is allowed to appear. - -Further to this, within this section, you can control which users can see a particular dashboard based on the *User Groups* they belong to. This is done by setting the 'access' permissions based on the *User Group* alias, you choose to deny or grant a particular User Group's access to the dashboard. - -```json -{ - "dashboards": [ - { - "alias": "myCustomDashboard", - "view": "/App_Plugins/MyCustomDashboard/dashboard.html", - "sections": [ "content", "member", "settings" ], - "weight": -10, - "access": [ - { "deny": "translator" }, - { "grant": "admin" } - ] - } - ] -} -``` - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Dashboards; -using Umbraco.Cms.Core; - -namespace Umbraco.Docs.Samples.Web.Dashboards -{ - [Weight(-10)] - public class MyCustomDashboard : IDashboard - { - public string Alias => "myCustomDashboard"; - - public string[] Sections => new[] - { - Constants.Applications.Content, - Constants.Applications.Members, - Constants.Applications.Settings - }; - - public string View => "/App_Plugins/MyCustomDashboard/dashboard.html"; - - public IAccessRule[] AccessRules - { - get - { - var rules = new IAccessRule[] - { - new AccessRule {Type = AccessRuleType.Deny, Value = Constants.Security.TranslatorGroupAlias}, - new AccessRule {Type = AccessRuleType.Grant, Value = Constants.Security.AdminGroupAlias} - }; - return rules; - } - } - } -} -``` - -## Remove an Umbraco dashboard - -In previous versions of Umbraco if you wanted to remove or modify the order of a default dashboard you would amend the `config/dashboards.config` file on disk. - -You need to use code to create your own *composer* to remove a dashboard. It could be a c# class that can be used to organize and customize your Umbraco application to your own needs. For example - if you wanted to remove the 'Content Dashboard' you would create a RemoveDashboard composer like this: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Dashboards; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Docs.Samples.Web.Dashboards -{ - public class RemoveDashboard : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Dashboards().Remove(); - } - } -} -``` - -## Override an Umbraco Dashboard - -To modify the order of a default dashboard or change its permissions, you must first remove the default dashboard (see above), then add an overridden instance of the default dashboard. The overridden dashboard can then include your modifications. For example, if you wanted to deny the Writers group access to the default Redirect URL Management dashboard, you would create an override of RedirectUrlDashboard to add after removing the default dashboard. - -```csharp -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Dashboards; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Docs.Samples.Web.Dashboards -{ - public class MyDashboardComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Dashboards() - // Remove the default - .Remove() - // Add the overridden one - .Add(); - } - } - - // overridden redirect dashboard with custom rules - public class MyRedirectUrlDashboard : RedirectUrlDashboard, IDashboard - { - // override explicit implementation - IAccessRule[] IDashboard.AccessRules { get; } = new IAccessRule[] - { - new AccessRule {Type = AccessRuleType.Deny, Value = Constants.Security.WriterGroupAlias}, - new AccessRule {Type = AccessRuleType.Grant, Value = Constants.Security.AdminGroupAlias}, - new AccessRule {Type = AccessRuleType.Grant, Value = "marketing"} - }; - } -} -``` diff --git a/10/umbraco-cms/extending/database.md b/10/umbraco-cms/extending/database.md deleted file mode 100644 index b7518c1ae92..00000000000 --- a/10/umbraco-cms/extending/database.md +++ /dev/null @@ -1,483 +0,0 @@ ---- - -meta.Title: Umbraco Database -description: A guide to creating a custom Database table in Umbraco ---- - -# Creating a Custom Database Table - -It is possible to add custom database tables to your site to store additional data that should not be stored as normal content nodes. - -{% hint style="info" %} -If migrating to Umbraco 9 from Umbraco 8, you'll be able to use a similar method as was available in that version. You register a component in a composer, create a migration plan and run the plan to add the database table to the database. Learn more about composers in the [Composing](../implementation/composing.md) article. -{% endhint %} - -The end result looks like this: - -![Database result of a migration]() - -## Using a Composer and Component - -The following code sample shows how this is done using a composer and component. - -When migrating from verison 8 there are a few changes to be aware of. The first change is that namespace updates are dependencies that need to be passed to the `Upgrader.Execute()` method. Another is a change to the access modifier of the `Migrate()` method. - -{% tabs %} -{% tab title="Latest version" %} -```csharp -using Microsoft.Extensions.Logging; -using NPoco; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Migrations; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Migrations; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade; -using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; - -namespace MyNamespace -{ - public class BlogCommentsComposer : ComponentComposer, IComposer - { - } - - public class BlogCommentsComponent : IComponent - { - private readonly ICoreScopeProvider _coreScopeProvider; - private readonly IMigrationPlanExecutor _migrationPlanExecutor; - private readonly IKeyValueService _keyValueService; - private readonly IRuntimeState _runtimeState; - - public BlogCommentsComponent( - ICoreScopeProvider coreScopeProvider, - IMigrationPlanExecutor migrationPlanExecutor, - IKeyValueService keyValueService, - IRuntimeState runtimeState) - { - _coreScopeProvider = coreScopeProvider; - _migrationPlanExecutor = migrationPlanExecutor; - _keyValueService = keyValueService; - _runtimeState = runtimeState; - } - - public void Initialize() - { - if (_runtimeState.Level < RuntimeLevel.Run) - { - return; - } - - // Create a migration plan for a specific project/feature - // We can then track that latest migration state/step for this project/feature - var migrationPlan = new MigrationPlan("BlogComments"); - - // This is the steps we need to take - // Each step in the migration adds a unique value - migrationPlan.From(string.Empty) - .To("blogcomments-db"); - - // Go and upgrade our site (Will check if it needs to do the work or not) - // Based on the current/latest step - var upgrader = new Upgrader(migrationPlan); - upgrader.Execute(_migrationPlanExecutor, _coreScopeProvider, _keyValueService); - } - - public void Terminate() - { - } - } - - public class AddCommentsTable : MigrationBase - { - public AddCommentsTable(IMigrationContext context) : base(context) - { - } - protected override void Migrate() - { - Logger.LogDebug("Running migration {MigrationStep}", "AddCommentsTable"); - - // Lots of methods available in the MigrationBase class - discover with this. - if (TableExists("BlogComments") == false) - { - Create.Table().Do(); - } - else - { - Logger.LogDebug("The database table {DbTable} already exists, skipping", "BlogComments"); - } - } - - [TableName("BlogComments")] - [PrimaryKey("Id", AutoIncrement = true)] - [ExplicitColumns] - public class BlogCommentSchema - { - [PrimaryKeyColumn(AutoIncrement = true, IdentitySeed = 1)] - [Column("Id")] - public int Id { get; set; } - - [Column("BlogPostUmbracoId")] - public int BlogPostUmbracoId { get; set; } - - [Column("Name")] - public string Name { get; set; } - - [Column("Email")] - public string Email { get; set; } - - [Column("Website")] - public string Website { get; set; } - - [Column("Message")] - [SpecialDbType(SpecialDbTypes.NVARCHARMAX)] - public string Message { get; set; } - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -using Microsoft.Extensions.Logging; -using NPoco; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Migrations; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Migrations; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade; -using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; - -namespace MyNamespace -{ - public class BlogCommentsComposer : ComponentComposer, IComposer - { - } - - public class BlogCommentsComponent : IComponent - { - private readonly IScopeProvider _scopeProvider; - private readonly IMigrationPlanExecutor _migrationPlanExecutor; - private readonly IKeyValueService _keyValueService; - private readonly IRuntimeState _runtimeState; - - public BlogCommentsComponent( - IScopeProvider scopeProvider, - IMigrationPlanExecutor migrationPlanExecutor, - IKeyValueService keyValueService, - IRuntimeState runtimeState) - { - _scopeProvider = scopeProvider; - _migrationPlanExecutor = migrationPlanExecutor; - _keyValueService = keyValueService; - _runtimeState = runtimeState; - } - - public void Initialize() - { - if (_runtimeState.Level < RuntimeLevel.Run) - { - return; - } - - // Create a migration plan for a specific project/feature - // We can then track that latest migration state/step for this project/feature - var migrationPlan = new MigrationPlan("BlogComments"); - - // This is the steps we need to take - // Each step in the migration adds a unique value - migrationPlan.From(string.Empty) - .To("blogcomments-db"); - - // Go and upgrade our site (Will check if it needs to do the work or not) - // Based on the current/latest step - var upgrader = new Upgrader(migrationPlan); - upgrader.Execute(_migrationPlanExecutor, _scopeProvider, _keyValueService); - } - - public void Terminate() - { - } - } - - public class AddCommentsTable : MigrationBase - { - public AddCommentsTable(IMigrationContext context) : base(context) - { - } - protected override void Migrate() - { - Logger.LogDebug("Running migration {MigrationStep}", "AddCommentsTable"); - - // Lots of methods available in the MigrationBase class - discover with this. - if (TableExists("BlogComments") == false) - { - Create.Table().Do(); - } - else - { - Logger.LogDebug("The database table {DbTable} already exists, skipping", "BlogComments"); - } - } - - [TableName("BlogComments")] - [PrimaryKey("Id", AutoIncrement = true)] - [ExplicitColumns] - public class BlogCommentSchema - { - [PrimaryKeyColumn(AutoIncrement = true, IdentitySeed = 1)] - [Column("Id")] - public int Id { get; set; } - - [Column("BlogPostUmbracoId")] - public int BlogPostUmbracoId { get; set; } - - [Column("Name")] - public string Name { get; set; } - - [Column("Email")] - public string Email { get; set; } - - [Column("Website")] - public string Website { get; set; } - - [Column("Message")] - [SpecialDbType(SpecialDbTypes.NVARCHARMAX)] - public string Message { get; set; } - } - } -} -``` -{% endtab %} -{% endtabs %} - -## Using a Notification Handler - -If building a new solution, you can adopt a new pattern. With this pattern you create and run a similar migration but trigger it in response to a [notification handler](../fundamentals/code/subscribing-to-notifications.md). - -The code for this approach is as follows: - -{% tabs %} -{% tab title="Latest version" %} -``` -using Microsoft.Extensions.Logging; -using NPoco; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Migrations; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Migrations; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade; -using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; - -namespace MyNamespace -{ - public class RunBlogCommentsMigration : INotificationHandler - { - private readonly IMigrationPlanExecutor _migrationPlanExecutor; - private readonly ICoreScopeProvider _coreScopeProvider; - private readonly IKeyValueService _keyValueService; - private readonly IRuntimeState _runtimeState; - - public RunBlogCommentsMigration( - ICoreScopeProvider coreScopeProvider, - IMigrationPlanExecutor migrationPlanExecutor, - IKeyValueService keyValueService, - IRuntimeState runtimeState) - { - _migrationPlanExecutor = migrationPlanExecutor; - _coreScopeProvider = coreScopeProvider; - _keyValueService = keyValueService; - _runtimeState = runtimeState; - } - - public void Handle(UmbracoApplicationStartingNotification notification) - { - if (_runtimeState.Level < RuntimeLevel.Run) - { - return; - } - - // Create a migration plan for a specific project/feature - // We can then track that latest migration state/step for this project/feature - var migrationPlan = new MigrationPlan("BlogComments"); - - // This is the steps we need to take - // Each step in the migration adds a unique value - migrationPlan.From(string.Empty) - .To("blogcomments-db"); - - // Go and upgrade our site (Will check if it needs to do the work or not) - // Based on the current/latest step - var upgrader = new Upgrader(migrationPlan); - upgrader.Execute( - _migrationPlanExecutor, - _coreScopeProvider, - _keyValueService); - } - } - - // Migration and schema defined as in the previous code sample. -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -``` -using Microsoft.Extensions.Logging; -using NPoco; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Migrations; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Migrations; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade; -using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; - -namespace MyNamespace -{ - public class RunBlogCommentsMigration : INotificationHandler - { - private readonly IMigrationPlanExecutor _migrationPlanExecutor; - private readonly IScopeProvider _scopeProvider; - private readonly IKeyValueService _keyValueService; - private readonly IRuntimeState _runtimeState; - - public RunBlogCommentsMigration( - IScopeProvider scopeProvider, - IMigrationPlanExecutor migrationPlanExecutor, - IKeyValueService keyValueService, - IRuntimeState runtimeState) - { - _migrationPlanExecutor = migrationPlanExecutor; - _scopeProvider = scopeProvider; - _keyValueService = keyValueService; - _runtimeState = runtimeState; - } - - public void Handle(UmbracoApplicationStartingNotification notification) - { - if (_runtimeState.Level < RuntimeLevel.Run) - { - return; - } - - // Create a migration plan for a specific project/feature - // We can then track that latest migration state/step for this project/feature - var migrationPlan = new MigrationPlan("BlogComments"); - - // This is the steps we need to take - // Each step in the migration adds a unique value - migrationPlan.From(string.Empty) - .To("blogcomments-db"); - - // Go and upgrade our site (Will check if it needs to do the work or not) - // Based on the current/latest step - var upgrader = new Upgrader(migrationPlan); - upgrader.Execute( - _migrationPlanExecutor, - _scopeProvider, - _keyValueService); - } - } - - // Migration and schema defined as in the previous code sample. -} -``` -{% endtab %} -{% endtabs %} - -The notification handler can be registered in a composer: - -``` -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Notifications; - -namespace TableMigrationTest -{ - public class BlogCommentsComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } - } -} -``` - -## Which to use? - -In short, it's up to you. If you are migrating from version 8 and want the quickest route to getting running with the latest version, then using a component makes sense. - -You will be using the notification pattern elsewhere. This could be when responding to Umbraco events that run many times in the lifetime of the application, like when content is saved. And so you may also prefer to align with that pattern for start-up events. - -It is also worth noting that components offer both `Initialize` and `Terminate` methods. With these you will need to handle two notifications to do the same with the notification handler approach (`UmbracoApplicationStartingNotification` and `UmbracoApplicationStoppingNotification`). A single handler class can be used for both notifications though. - -## Schema Class and Migrations - -**Important!** The `BlogCommentSchema` class nested inside the migration is purely used as a database schema representation class. It should not be used as a Data Transfer Object (DTO) to access the table data. Equally, you shouldn't use your DTO classes to define the schema used by your migration. Instead, you should create a duplicate snapshot for the purpose of creating or working with your database tables in the current migration. The name of the class is not important as you will be overriding it using the TableName attribute. You should choose a name that makes it clear that this class is purely for defining the schema in this migration. - -Whilst this adds a level of duplication, it is important that migrations and the code/classes within a migration remain immutable. If the DTO was to be used for both, it could cause unexpected behaviour. Should you later modify your DTO used in your application but you have previous migrations expecting the DTO to be in its unmodified state. - -Once a snapshot has been created, and once your code has been deployed, the snapshot should never be changed directly. Instead, you should use further migrations to alter the database table into the state you require. This ensures that migrations can be run in sequence and that each migration can expect the database to be in a known state before executing. - -When adding further migrations and if you need to reuse the schema class, it is a good idea to duplicate this in those particular migrations. You want the migrations to be immutable. Having separate classes in separate namespaces, reduces the risk of modifying a schema class from your initial migration. - -## Data stored in Custom Database Tables - -When storing data in custom database tables, this is by default not manageable by Umbraco at all. This can be great for many purposes such as storing massive amounts of data that you do not need to edit from the backoffice. Decoupling part of your data from being managed by Umbraco as content can be a way of achieving better performance for your site. It will no longer take up space in indexes and caches, and the Umbraco database. - -This also means that if you do need to edit or display this data, you need to implement the underlying functionality to support this. The same if the case if you need this data to be transferred or kept synchronized between multiple sites or environments. Data stored in custom tables are not supported by default by add-ons such as Umbraco Deploy and will not be deployable by default. - -Figuring out how to manage data across multiple environments can be different between individual sites and there is not one solution that fits all. Some sites may have automated database synchronization set up to ensure specific tables in multiple databases are always kept in sync. Other sites may be better off with scripts moving data around manually on demand. - -## Working with data in Custom Database Tables - -To create, read, update or delete data from your custom database tables, you can use the `IScopeProvider` to get access to the database operations. - -The following example creates an `UmbracoApiController` to be able to fetch and insert blog comments. - -{% hint style="warning" %} -This example does not use the aforementioned `BlogCommentSchema` class but rather a separate (yet duplicate) class that is not part of the example. Also, be aware that things like error handling and data validation have been omitted for brevity. -{% endhint %} - -```C# -using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; -using Umbraco.Cms.Infrastructure.Scoping; -using Umbraco.Cms.Web.Common.Controllers; -namespace MyNamespace -{ - public class BlogCommentsApiController : UmbracoApiController - { - private readonly IScopeProvider _scopeProvider; - public BlogCommentsApiController(IScopeProvider scopeProvider) - { - _scopeProvider = scopeProvider; - } - [HttpGet] - public IEnumerable GetComments(int umbracoNodeId) - { - using var scope = _scopeProvider.CreateScope(); - var queryResults = scope.Database.Fetch("SELECT * FROM BlogComments WHERE BlogPostUmbracoId = @0", umbracoNodeId); - scope.Complete(); - return queryResults; - } - [HttpPost] - public void InsertComment(BlogComment comment) - { - using var scope = _scopeProvider.CreateScope(); - scope.Database.Insert(comment); - scope.Complete(); - } - } -} -``` diff --git a/10/umbraco-cms/extending/embedded-media-providers.md b/10/umbraco-cms/extending/embedded-media-providers.md deleted file mode 100644 index 19ed33f6d76..00000000000 --- a/10/umbraco-cms/extending/embedded-media-providers.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -description: A guide to creating a custom embed providers in Umbraco ---- - -# Embedded Media Providers - -The Rich Text Editor in Umbraco has an 'Embed' button, that when pressed, slides open a panel. This panel enables editors to paste the URL of a third-party media resource to embed in content. - -![The Rich Text Editor Embed Button](<../.gitbook/assets/Embed-Button (1).png>) - -For example, a YouTube Video... - -![Embedding a music video from YouTube](<../.gitbook/assets/Embed-YouTube (1).png>) - -The task of an `EmbedProvider` is to accept the pasted URL and write out the appropriate markup for the third-party provider associated with the URL. - -## Embed Provider Configuration - -Embed Providers are registered with the `EmbedProvidersCollection` during Composition when Umbraco boots. - -The list of available default Embed Providers in an Umbraco install are as follows: - -* YouTube -* YouTube Shorts -* Twitter -* Vimeo -* Dailymotion -* Flickr -* SlideShare -* Kickstarter -* Getty Images -* Ted -* SoundCloud -* Issuu -* Hulu -* Giphy - -You can see the details of these, and any recent editions in the C# developer reference for [Umbraco.Web.Media.EmbedProviders](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Media.EmbedProviders.html). - -## Configuring a new provider - -Create a new provider by creating a C# class that implements the `IEmbedProvider` interface. Umbraco provides a convenient `OEmbedProviderBase` class as a starting point. - -```csharp -namespace Umbraco.Cms.Core.Media.EmbedProviders; - -public abstract class OEmbedProviderBase : IEmbedProvider -{ - protected OEmbedProviderBase(IJsonSerializer jsonSerializer); - - public abstract string ApiEndpoint { get; } - public abstract string[] UrlSchemeRegex { get; } - public abstract Dictionary RequestParams { get; } - - public abstract string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0); - public virtual string GetEmbedProviderUrl(string url, int maxWidth, int maxHeight); - public virtual string DownloadResponse(string url); - public virtual T? GetJsonResponse(string url) where T : class; - public virtual XmlDocument GetXmlResponse(string url); - public virtual string GetXmlProperty(XmlDocument doc, string property); -} -``` - -### Adding a new OEmbed Provider Example - -Let's allow our editors to embed artwork from the popular DeviantArt website - the world's largest online social community for artists and art enthusiasts. We can see they have information on using OEmbed: [https://www.deviantart.com/developers/oembed](https://www.deviantart.com/developers/oembed). The format of their OEmbed implementation returns a JSON format, from a URL `https://backend.deviantart.com/oembed?url=[urltoembed]`. We'll need to use the `OEmbedProviderBase` and the `base.GetJsonResponse` method. We can see 'links' to media shared on DeviantArt are in the format: `https://fav.me/[uniquemediaidentifier]`. We'll need a regex to match any URLs pasted into the embed panel that start with _fav.me_, achieved by setting the `UrlSchemeRegex` property. - -The Provider would look like this: - -```csharp -using Umbraco.Cms.Core.Media.EmbedProviders; -using Umbraco.Cms.Core.Serialization; - -namespace MyNamespace; - -public class DeviantArtEmbedProvider : OEmbedProviderBase -{ - public DeviantArtEmbedProvider(IJsonSerializer jsonSerializer) - : base(jsonSerializer) - { - } - - public override string ApiEndpoint => "https://backend.deviantart.com/oembed?url="; - - public override string[] UrlSchemeRegex => new[] - { - @"fav\.me/*", - @"\w+\.deviantart.com\/\w+\/art\/*", - @"\w+\.deviantart.com\/art\/*", - @"sta\.sh/*", - @"\w+\.deviantart.com\/\w+#\/d*" - }; - - public override Dictionary RequestParams => new(); - - public override string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) - { - string requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); - OEmbedResponse? oembed = base.GetJsonResponse(requestUrl); - - return oembed?.GetHtml(); - } -} -``` - -#### Register the provider with the `EmbedProvidersCollection` - -Create a new C# class that implements `IComposer` and append your new provider to the `EmbedProvidersCollection`: - -```csharp -using Umbraco.Cms.Core.Composing; - -namespace MyNamespace; - -public class RegisterEmbedProvidersComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - => builder.EmbedProviders().Append(); -} -``` - -The new provider should be available for editors to use: - -![Embedding a Media Item from DeviantArt website](<../.gitbook/assets/deviantart-embedded-media (1).png>) - -Notice there isn't really any implementation written here. The regex maps the incoming URL to the provider. The base methods handle the complication of requesting from the third party API and turning the response into HTML. - -## Custom Embed Providers - -If your third-party media provider lacks OEmbed support or requires custom HTML due to content quirks, implement `GetMarkup()` without using base helper methods. - -### Custom Embed Provider Example - -Azure Media Services [(https://azure.microsoft.com/en-gb/services/media-services/)](https://azure.microsoft.com/en-gb/services/media-services/) provide 'broadcast-quality' video streaming services. You can embed the Azure Media Player into your site to play a video [using an IFrame](https://ampdemo.azureedge.net/azuremediaplayer.html). - -You can create a custom `EmbedProvider` to embed an IFrame video player in your content. This can be done by taking the Media asset URL and writing out the required markup. - -```csharp -using System.Net; -using Umbraco.Cms.Core.Media.EmbedProviders; -using Umbraco.Cms.Core.Serialization; - -namespace MyNamespace; - -public class AzureVideoEmbedProvider : OEmbedProviderBase -{ - public AzureVideoEmbedProvider(IJsonSerializer jsonSerializer) - : base(jsonSerializer) - { - } - - // no ApiEndpoint! - public override string ApiEndpoint => string.Empty; - - public override string[] UrlSchemeRegex => new[] - { - @"windows\.net/*" - }; - - public override Dictionary RequestParams => new(); - - public override string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) - { - // format of markup - string videoFormat = "
"; - - // pass in encoded Url, with and height, and turn off autoplay... - var videoPlayerMarkup = string.Format(videoFormat, WebUtility.UrlEncode(url) + "&autoplay=false", maxWidth, maxHeight); - - return videoPlayerMarkup; - } -} -``` - -Here the markup to embed has been manually constructed based upon the iframe video player, no request to an Api endpoint is made... - -#### Register the Azure Embed Provider with the `EmbedProvidersCollection` - -Create a new C# class that implements `IComposer` and add append your new provider to the `EmbedProvidersCollection`: - -```csharp -using Umbraco.Cms.Core.Composing; - -namespace MyNamespace; - -public class RegisterEmbedProvidersComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - => builder.EmbedProviders().Append(); -} -``` - -Now editors can embed Azure Media video Urls in the format: `//amssamples.streaming.mediaservices.windows.net/3b970ae0-39d5-44bd-b3a3-3136143d6435/AzureMediaServicesPromo.ism/manifest`. diff --git a/10/umbraco-cms/extending/filesystemproviders/README.md b/10/umbraco-cms/extending/filesystemproviders/README.md deleted file mode 100644 index e1caa4a2d54..00000000000 --- a/10/umbraco-cms/extending/filesystemproviders/README.md +++ /dev/null @@ -1,235 +0,0 @@ ---- - -meta.Title: "Umbraco File System Providers" -description: "A guide to creating custom file systems in Umbraco" ---- - -# Custom file systems (IFileSystem) - -## Media Filesystem - -{% hint style="info" %} -Before considering a custom media file system, be sure to first read about the configuration options for `UmbracoMediaPath` and `UmbracoMediaPhysicalRootPath` in the [configuration reference docs](../../reference/configuration/globalsettings.md). These configurations may save you from creating your own media file system entirely. -{% endhint %} - -By default, Umbraco uses an instance of `PhysicalFileSystem` to handle the storage location of the media archive (wwwroot/media). - -This can be configured by composition: - -```csharp -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Infrastructure.DependencyInjection; - -namespace UmbracoExamples.Composition -{ - public class SetMediaFileSystemComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.SetMediaFileSystem((factory) => - { - IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); - var folderLocation = "~/CustomMediaFolder"; - var rootPath = hostingEnvironment.MapPathWebRoot(folderLocation); - var rootUrl = hostingEnvironment.ToAbsolute(folderLocation); - - return new PhysicalFileSystem( - factory.GetRequiredService(), - hostingEnvironment, - factory.GetRequiredService>(), - rootPath, - rootUrl); - }); - } - } -} -``` - -When creating a `PhysicalFileSystem` it takes some dependencies like `IIOHelper`, but the last two parameters are what we're interested in. - -The `rootPath` is where your media will be stored on the disk. Since netcore by default stores files in the `wwwroot`, we must put our desired folder somewhere within `wwwroot` to ensure that we use `hostingEnvironment.MapPathWebRoot(~/CustomMediaFolder)`. The `~` will be mapped to your `wwwroot` folder, so the final `rootPath` will be `your/project/path/wwwroot/CustomMediaFolder`. The `~` is therefore important. - -The `rootUrl` is the base URL that your media files will be served from. In this case, your image URL could look something like `mysite.com/CustomMediaFolder/MyAwesomePicture.png`. Again the `~` is important. - -In the code sample above, the `rootUrl` must map to the the same physical location as `rootPath`, which again must be placed under `wwwroot`. If you want to store the media files outside of `wwwroot` there is an extra step involved; you need to instruct netcore to include static files from a different physical location. - -The `rootUrl` is the base URL that your media files will be served from. In this case, your image URL could look something like `mysite.com/CustomMediaFolder/MyAwesomePicture.png`. Again the `~` is important. With the code sample above, the `rootUrl` must map to the same physical location as `rootPath`, otherwise, you will get 404's for your images. - -If you want to store the media files outside of `wwwroot` there is an extra step involved; you need to instruct netcore to include static files from a different physical location. - -In the `Configure` method in `startup.cs`, register a new static file location like so: - -```csharp -public void Configure(IApplicationBuilder app) -{ - ... - - app.UseStaticFiles(new StaticFileOptions - { - FileProvider = new PhysicalFileProvider(Path.Combine("C:", "storage", "umbracoMedia")), - RequestPath = "/CustomPath" - }); -} -``` - -The PhysicalFileProvider takes a single parameter, the **`RootPath`**. This is the rooted filesystem path using directory separator chars and not ending with a directory separator, eg: `c:\storage\umbracoMedia` or `\\server\path`. The safest way to achieve this is using `Path.Combine`. - -You also have to specify the **`RequestPath`**. This is the relative URL where the media will be served using URL separator chars and not ending with a separator, eg: `/CustomPath` or `/Media`. - -Now you can use your newly registered static file location as if it was `wwwroot`. Notice how you no longer need to use `hostingEnvironment.MapPathWebRoot(folderLocation)`, since you're no longer trying to map the location to somewhere within `wwwroot`, but instead use your newly registered static file location. - -```csharp -public void Compose(IUmbracoBuilder builder) -{ - builder.SetMediaFileSystem((factory) => - { - IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); - var rootPath = Path.Combine("C:", "storage", "umbracoMedia"); - var rootUrl = hostingEnvironment.ToAbsolute("/CustomPath"); - - return new PhysicalFileSystem( - factory.GetRequiredService(), - hostingEnvironment, - factory.GetRequiredService>(), - rootPath, - rootUrl); - }); -} -``` - -This is almost the same as when registering a location within the `wwwroot` folder. The only difference is that `rootPath` is now set to the path we gave the `PhysicalFileProvider` and the `rootUrl` is the same as we set as the `RequestPath` in the `StaticFileOption`. - -Our media is now stored in `C:\storage\umbracoMedia`, and is served from the base URL `/CustomPath`, so an image URL will look something like `mysite.com/CustomPath/MyAwesomePicture.png`. - -### Creating a custom file system - -You can replace `PhysicalFileSystem` with a custom file system implementation - eg. if you want your media files stored on Amazon S3 or elsewhere outside your site. - -To achieve this, you must first create your own file system by implementing the interfaces `IFileSystem` and `IFileProviderFactory` (the interfaces that are implemented by `PhysicalFileSystem`). - -You then replace the media filesystem by composition using `IUmbracoBuilder.SetMediaFileSystem(...)` (as is demonstrated in the paragraphs above), but instead of returning a `PhysicalFileSystem`, you return your own file system implementation. - -For inspiration on building a custom file system, have a look at the [Azure Blob Storage file system implementation](https://github.com/umbraco/Umbraco.StorageProviders#umbracostorageprovidersazureblob). - -### Accessing the media file system from code - -Since the default media file system can be swapped with custom implementations, you should never access the implementation directly. Umbraco uses a manager class called `MediaFileManager`. You can get a reference to this manager class via dependency injection in the constructor for your custom class or controller: - -```csharp -public class ImagesController : UmbracoAuthorizedApiController -{ - private readonly MediaFileManager _mediaFileManager; - - public ImagesController(MediaFileManager mediaFileManager) - { - _mediaFileManager = mediaFileManager; - } - -{...} -``` - -You can then access the configured file system provider through `_mediaFileManager.FileSystem`, which is the same way Umbraco will access the file system provider. - -## MediaPath Scheme - -The MediaPath Scheme defines the current set of rules that decide the format of the Media Path when it is saved into the media archive wherever it is located. - -By default the MediaPath scheme used by Umbraco is the `UniqueMediaPathScheme` this generates a unique 'folder' to place the uploaded image in eg. - -`/media/dozdrg2f/mylovelyimage.jpg` - -`/media` is defined by the PhysicalFileSystem and 'dozdrg2f' is generated by the `UniqueMediaPathScheme`. - -You can create your own logic for the path by implementing `IMediaPathScheme` and setting it during composition with: - -```csharp -builder.Services.AddUnique(); -``` - -{% hint style="info" %} -`OriginalMediaPathScheme` is deprecated as of Umbraco 9. If you are migrating from earlier versions, we recommend using `IMediaPathScheme` to implement your own logic. -{% endhint %} - -## Other IFileSystems - -Umbraco also registers instances of `PhysicalFileSystem` for the following parts of Umbraco that persist to 'files': - -- `MacroPartialsFileSystem` -- `PartialViewsFileSystem` -- `StylesheetsFileSystem` -- `ScriptsFileSystem` -- `MvcViewsFileSystem` - -These are accessible via dependency injection. - -```csharp -public class FileSystemLocations -{ - private readonly FileSystems _fileSystems; - public FileSystemLocations(FileSystems fileSystems) - { - _fileSystems = fileSystems; - var macroPartialsFileSystem = _fileSystems.MacroPartialsFileSystem; - } -``` - -`IFileSystem`, `MediaFileManager`, and `FileSystems` are located in the `Umbraco.Cms.Core.IO` namespace. - -### Stylesheet Filesystem - -Like with the media file system it is also possible to replace the stylesheet filesystem with your own implementation of `IFileSystem` in a composer. It's important to note here that, unlike media file system, you cannot replace the filesystem with a `PhysicalFileSystem` using a different root path or root URL, this will not work, and will cause issues since the root path is coupled to the virtual path, given by the frontend, e.g. `/css/MyBeautifulStyle.css`. - -When replacing the stylesheet filesystem, you don't need to register it, since it's only available through Filesystems, what you need to do instead is configure the `FileSystems` to use your implementation for the `StylesheetsFileSystem`. - -The IUmbracoBuilder has an extension method for configuring the `FileSystems`, you need to invoke this method with an action that accepts an `IServiceProvider` and the `FileSystems` you will configure, configuring the `FileSystems` can look like this: - -```c# -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Infrastructure.DependencyInjection; - -namespace UmbracoExamples.Composition -{ - public class FileSystemComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.ConfigureFileSystems((factory, systems) => - { - IIOHelper ioHelper = factory.GetRequiredService(); - IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); - ILogger logger = factory.GetRequiredService>(); - GlobalSettings settings = factory.GetRequiredService>().Value; - - var path = settings.UmbracoCssPath; - var rootPath = hostingEnvironment.MapPathWebRoot(path); - var rootUrl = hostingEnvironment.ToAbsolute(path); - var fileSystem = new YourFileSystemImplementation(ioHelper, hostingEnvironment, logger, rootPath, rootUrl); - - systems.SetStylesheetFilesystem(fileSystem); - }); - } - } -} -``` - -Where `YourFileSystemImplementation` is a class that implements `IFileSystem`. This should always be done in a composer, since we do not recommend trying to change filesystems on the fly. - -After the `SetStylesheetFileSystem` method has run, `FileSystems.StylesheetsFileSystem` will return the instance that was created in the `ConfigureFileSystems` extension method. - -## Custom providers - -There is an Azure Blob Storage provider: - -- [Azure Blob Storage](azure-blob-storage.md) diff --git a/10/umbraco-cms/extending/filesystemproviders/azure-blob-storage.md b/10/umbraco-cms/extending/filesystemproviders/azure-blob-storage.md deleted file mode 100644 index 92b5a3a7250..00000000000 --- a/10/umbraco-cms/extending/filesystemproviders/azure-blob-storage.md +++ /dev/null @@ -1,135 +0,0 @@ ---- - -meta.Title: "Using Azure Blob Storage for Media and ImageSharp Cache" -description: "Setup your site to use Azure Blob storage for media and ImageSharp cache" ---- - -# Setup Your Site to use Azure Blob Storage for Media and ImageSharp Cache - -There are some scenarios where you may want or need to consider leveraging Azure Blob Storage. An example would be for media in Umbraco sites with substantial media libraries. - -Having your site's media in Azure Blob Storage can help your deployments complete more quickly. This has the potential to positively affect site performance, as the ImageSharp cache is moved to Azure Blob Storage. - -The setup consists of adding a package to your site, setting the correct configuration, and adding the services and middleware. Before you begin you’ll need to create an Azure Storage Account and a container for your media and ImageSharp cache. In this example, we assume your container name is "mysitestorage" and has already been created. - -See the [Microsoft documentation](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal) for a quickstart guide on how to create a blob storage container. - -## Installing the package - -Before you begin, you need to install the `Umbraco.StorageProviders.AzureBlob` NuGet package. There are two approaches to installing the package: - -1. Use your favorite IDE and open up the NuGet Package Manager to search and install the package -1. Use the command line to install the package - -### Installing through command line - -Navigate to your project folder, which is the folder that contains your `.csproj` file. Now use the following `dotnet add package` command to install the package: - -{% tabs %} -{% tab title="Latest version" %} -```none -dotnet add package Umbraco.StorageProviders.AzureBlob -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```none -dotnet add package Umbraco.StorageProviders.AzureBlob --version 1.1.1 -``` -{% endtab %} -{% endtabs %} - - -The correct package will have be installed in your project. - -## Configuring Blob storage - -The next step is to configure your blob storage. There are multiple approaches for this, but in this document, we're going to do it through `appsettings.json`. For more configuration options, see the [readme](https://github.com/umbraco/Umbraco.StorageProviders#umbracostorageproviders) on the GitHub repository. - -Open up your `appsettings.json` file and add the connection string and container name under `Umbraco:Storage:AzureBlob:Media`. Your Umbraco section of appsettings will look something like this: - -```json - "Umbraco": { - "Storage": { - "AzureBlob": { - "Media": { - "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=;AccountKey=;EndpointSuffix=core.windows.net", - "ContainerName": "mysitestorage" - } - } - }, - "CMS": { - "Hosting": { - "Debug": false - }, - {...} - } - } -``` - -In this example, the container name is `mysitestorage`. - -{% hint style="info" %} -You can get your connection string from your Azure Portal under "Access Keys". -{% endhint %} - -## Setting the services and middleware - -You're almost there. The last step is to set up the required services and middleware. This may sound daunting, but thankfully there are extension methods that do all this for you. All you need to do is invoke them in the `ConfigureServices` and `Configure` methods in the `startup.cs` file. - -Invoke the `.AddAzureBlobMediaFileSystem()` extension method in the `ConfigureServices` method: - -```C# - public void ConfigureServices(IServiceCollection services) - { -#pragma warning disable IDE0022 // Use expression body for methods - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddAzureBlobMediaFileSystem() // This configures the required services - .Build(); -#pragma warning restore IDE0022 // Use expression body for methods - - } -``` - -{% hint style="info" %} -**If you are using Umbraco 9, follow this step before moving on**: - -Next invoke `UseAzureBlobMediaFileSystem();` in the `.WithMiddleware` call, like so: - -```C# -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseUmbraco() - .WithMiddleware(u => - { - u.UseBackOffice(); - u.UseWebsite(); - // This enables the Azure Blob storage middleware for media. - u.UseAzureBlobMediaFileSystem(); - }) - .WithEndpoints(u => - { - u.UseInstallerEndpoints(); - u.UseBackOfficeEndpoints(); - u.UseWebsiteEndpoints(); - }); -} -``` -{% endhint %} - -Now when you launch your site again, the blob storage will be used to store media items as well as the ImageSharp cache. Do note though that the `/media` and `/cache` folders do not get created until a piece of media is uploaded. - - -## Existing Media files - -Any media files you already have on your site will not automatically be added to the blob storage container. You will need to copy the contents on the `/wwwroot/media` folder and upload them to a new folder called `/media` in your blob storage container. Once you've done that, you can safely delete the `wwwroot/media` folder locally, as it is no longer needed. - -Any new media files you upload to the site will automatically be added to the Blob Storage. diff --git a/10/umbraco-cms/extending/filesystemproviders/images/config-from-backoffice.png b/10/umbraco-cms/extending/filesystemproviders/images/config-from-backoffice.png deleted file mode 100644 index a28c4f9bb7e..00000000000 Binary files a/10/umbraco-cms/extending/filesystemproviders/images/config-from-backoffice.png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/README.md b/10/umbraco-cms/extending/health-check/README.md deleted file mode 100644 index 138cafaacca..00000000000 --- a/10/umbraco-cms/extending/health-check/README.md +++ /dev/null @@ -1,416 +0,0 @@ ---- - - -meta.Title: Umbraco Healthcheck -description: >- - The Settings section of the Umbraco backoffice holds a dashboard named 'Health - Check'. It is a handy list of checks to see if your Umbraco installation is - configured according to best practices. ---- - -# Health Check - -The Settings section of the Umbraco backoffice holds a dashboard named "Health Check". It is a handy list of checks to see if your Umbraco installation is configured according to best practices. It's possible to add your custom-built health checks. - -For inspiration when building your checks you can look at the checks we've [built into Umbraco](https://github.com/umbraco/Umbraco-CMS/tree/v10/dev/src/Umbraco.Core/HealthChecks/Checks), as well as our [guides](guides/). Some examples will follow in this document. - -## Built-in checks - -Umbraco comes with the following checks by default: - -* Category **Configuration** - * **Macro errors (id: `D0F7599E-9B2A-4D9E-9883-81C7EDC5616F`)** - checks that the errors are set to `inline` so that pages that error will still load (and shows a small error message) - * **Notification Email Settings (id: `3E2F7B14-4B41-452B-9A30-E67FBC8E1206`)** - checks that the "from" email address used for email notifications has been changed from its default value -* Category **Data Integrity** - * **Database data integrity check (id: `73DD0C1C-E0CA-4C31-9564-1DCA509788AF`)** - checks for data integrity issues in the Umbraco database -* Category **Live Environment** - * **Debug Compilation Mode (id: `61214FF3-FC57-4B31-B5CF-1D095C977D6D`)** - should be set to `debug="false"` on your live site -* Category **Permissions** - * **Folder & File Permissions (id: `53DBA282-4A79-4B67-B958-B29EC40FCC23`)** - checks that the folders and files set with write permissions that are either required or recommended can be accessed -* Category **Security** - * **Application URL Configuration (id: `6708CA45-E96E-40B8-A40A-0607C1CA7F28`)** - checks if the Umbraco application URL is configured for your site. - * **Click-Jacking Protection (id: `ED0D7E40-971E-4BE8-AB6D-8CC5D0A6A5B0`)** - checks to see if a header or meta-tag is in place to indicate whether the site can be hosted in an IFRAME. Normally this is best set to deny permission for this to be done, to prevent what is known as [click-jacking](https://www.owasp.org/index.php/Clickjacking) attacks - * **Content/MIME Sniffing Protection (id: `1CF27DB3-EFC0-41D7-A1BB-EA912064E071`)** - checks that your site contains a header used to protect against Multipurpose Internet Mail Extensions (MIME) sniffing vulnerabilities - * **Cookie hijacking and protocol downgrade attacks Protection (HSTS) (id: `E2048C48-21C5-4BE1-A80B-8062162DF124`)** - checks if your HTTPS site contains the Strict-Transport-Security Header (HSTS). If not - adds with a default of 18 weeks - * **Cross-site scripting Protection (id: `F4D2B02E-28C5-4999-8463-05759FA15C3A`)** - checks for the presence of the X-XSS-Protection-header - * **Excessive Headers (id: `92ABBAA2-0586-4089-8AE2-9A843439D577`)** - checks to ensure that specific headers that can provide details about the technology used to build and host the website have been removed - * **HTTPS Configuration (id: `EB66BB3B-1BCD-4314-9531-9DA2C1D6D9A7`)** - to determine if the current site is running on a secure connection - * **UseHttps check** - when the site is running on HTTPS, `Umbraco.Cms.Core.Configuration.Models.GlobalSettings.UseHttps` needs to be enabled to secure the backoffice. The setting can be found under `Umbraco:CMS:Global` in the `appsettings.json` file -* Category **Services** - * **SMTP Settings (id: `1B5D221B-CE99-4193-97CB-5F3261EC73DF`)** - checks that an Simple Mail Transfer Protocol (SMTP) server is configured and is accepting requests for sending emails - -Each check returns a message indicating whether or not the issue in question has been found on the website installation. This could be an error that should be fixed, or a warning you should be aware of. - -Some of them can also be rectified via the dashboard, by clicking the **Fix** button and in some cases providing some required information. These changes usually involve writing to configuration files that will often trigger a restart of the website. - -## Configuring and scheduling checks - -You can view the results of health checks via the Settings section dashboard. Additionally, you can set up the checks to be run on a schedule and be notified of the results by email. It's also possible to disable certain checks if they aren't applicable in your environment. - -For more information, see the [Reference > Configuration > Health checks](../../reference/configuration/healthchecks.md) article. - -## Custom checks - -You can build your own health checks. There are two types of health checks you can build: **configuration checks** and **general checks**. - -Each health check is a class that needs to have a `HealthCheck` attribute. This attribute has a few things you need to fill in: - -* GUID - a unique ID that you've generated for this specific check -* Name - give it a short name so people know what the check is for -* Description - describes what the check does in detail -* Group - this is the category for the check if you use an existing group name (like "Configuration") the check will be added in that category, otherwise a new category will appear in the dashboard - -### Configuration checks - -These are small checks that take an [IConfiguration](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.iconfiguration?view=dotnet-plat-ext-6.0) key and confirm that the value that's expected is there. If the value is not correct, there will be a link to a guide on how to set this value correct. - -* A configuration check needs to inherit from `Umbraco.Cms.Core.HealthChecks.Checks.AbstractSettingsCheck` -* A configuration check needs the `HealthCheck` attribute as noted at the start of this document -* `ReadMoreLink` is a link to an external guide that will help you to troubleshoot any problems -* `ValueComparisonType` can either be `ValueComparisonType.ShouldEqual` or `ValueComparisonType.ShouldNotEqual` -* `ItemPath` is the IConfiguration key path leading to the configuration value that you want to verify -* `Values` is a list of values that are available for this configuration item - in this example it can be `RemoteOnly` or `On`, they're both acceptable for a live site. - * For checks using the `ShouldEqual` comparison method, make sure to set one of these values to `IsRecommended = true`. - * Where `ShouldNotEqual` is used the fix will require the user to provide the correct setting -* `CurrentValue` is the current value from the configuration setting -* `CheckSuccessMessage` and `CheckErrorMessage` are the messages returned to the user - * It is highly recommended to use the `LocalizedTextService` so these can be localized. You can add the text in `~/Config/Lang/en-US.user.xml` (or whatever language you like) - -An example check: - -```csharp -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Macros; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Core.HealthChecks.Checks.Configuration -{ - /// - /// Health check for the recommended production configuration for Macro Errors. - /// - [HealthCheck( - "D0F7599E-9B2A-4D9E-9883-81C7EDC5616F", - "Macro errors", - Description = "Checks to make sure macro errors are not set to throw a YSOD (yellow screen of death), which would prevent certain or all pages from loading completely.", - Group = "Configuration")] - public class MacroErrorsCheck : AbstractSettingsCheck - { - private readonly ILocalizedTextService _textService; - private readonly IOptionsMonitor _contentSettings; - - /// - /// Initializes a new instance of the class. - /// - public MacroErrorsCheck( - ILocalizedTextService textService, - IOptionsMonitor contentSettings) - : base(textService) - { - _textService = textService; - _contentSettings = contentSettings; - } - - /// - public override string ReadMoreLink => Constants.HealthChecks.DocumentationLinks.Configuration.MacroErrorsCheck; - - /// - public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual; - - /// - public override string ItemPath => Constants.Configuration.ConfigContentMacroErrors; - - /// - /// Gets the values to compare against. - /// - public override IEnumerable Values - { - get - { - var values = new List - { - new AcceptableConfiguration - { - IsRecommended = true, - Value = MacroErrorBehaviour.Inline.ToString() - }, - new AcceptableConfiguration - { - IsRecommended = false, - Value = MacroErrorBehaviour.Silent.ToString() - } - }; - - return values; - } - } - - /// - public override string CurrentValue => _contentSettings.CurrentValue.MacroErrors.ToString(); - - /// - /// Gets the message for when the check has succeeded. - /// - public override string CheckSuccessMessage => - _textService.Localize( - "healthcheck","macroErrorModeCheckSuccessMessage", - new[] { CurrentValue, Values.First(v => v.IsRecommended).Value }); - - /// - /// Gets the message for when the check has failed. - /// - public override string CheckErrorMessage => - _textService.Localize( - "healthcheck","macroErrorModeCheckErrorMessage", - new[] { CurrentValue, Values.First(v => v.IsRecommended).Value }); - } -} -``` - -### General checks - -This can be anything you can think of, the results and the rectify action are entirely under your control. - -* A general check needs to inherit from `Umbraco.Cms.Core.HealthChecks.HealthCheck` -* A general check needs the `HealthCheck` attribute as noted at the start of this document -* All checks run when the dashboard is loaded, this means that the `GetStatus()` method gets executed - * You can return multiple status checks from `GetStatus()` -* A status check returns a `HealthCheckStatus` - * If a `HealthCheckStatus` has a `HealthCheckAction` defined then the "Fix" button will perform that action once clicked - * Sometimes, the button to fix something should not be called "Fix", change the `Name` property of a `HealthCheckAction` to provide a better name - * `HealthCheckAction` has a `Description` property so that you can provide information on what clicking the "Rectify" button will do (or provide links to documentation, for example) - * `HealthCheckStatus` has a few result levels: - * `StatusResultType.Success` - * `StatusResultType.Error` - * `StatusResultType.Warning` - * `StatusResultType.Info` - * A `HealthCheckAction` needs to provide an alias for an action that can be picked up in the `ExecuteAction` method -* It is highly recommended to use the `LocalizedTextService` so text can be localized. You can add the text in `~/Config/Lang/en-US.user.xml` (or whatever language you like) - -An example check: - -```csharp -using Umbraco.Cms.Core.HealthChecks; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Extensions; -using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; - -namespace Umbraco.Web.HealthCheck.Checks.SEO; - -[HealthCheck("3A482719-3D90-4BC1-B9F8-910CD9CF5B32", "Robots.txt", - Description = "Create a robots.txt file to block access to system folders.", - Group = "SEO")] -public class RobotsTxt : Cms.Core.HealthChecks.HealthCheck -{ - private readonly IHostingEnvironment _hostingEnvironment; - private readonly ILogger _logger; - private readonly ILocalizedTextService _textService; - - public RobotsTxt(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, - ILogger logger) - { - _textService = textService; - _hostingEnvironment = hostingEnvironment; - _logger = logger; - } - - public override Task> GetStatus() => - Task.FromResult((IEnumerable)new[] { CheckForRobotsTxtFile() }); - - public override HealthCheckStatus ExecuteAction(HealthCheckAction action) - { - switch (action.Alias) - { - case "addDefaultRobotsTxtFile": - return AddDefaultRobotsTxtFile(); - default: - throw new InvalidOperationException("Action not supported"); - } - } - - private HealthCheckStatus CheckForRobotsTxtFile() - { - var success = File.Exists(_hostingEnvironment.MapPathContentRoot("~/robots.txt")); - var message = success - ? _textService.Localize("healthcheck", "seoRobotsCheckSuccess") - : _textService.Localize("healthcheck","seoRobotsCheckFailed"); - - var actions = new List(); - - if (success == false) - { - actions.Add(new HealthCheckAction("addDefaultRobotsTxtFile", Id) - // Override the "Rectify" button name and describe what this action will do - { - Name = _textService.Localize("healthcheck","seoRobotsRectifyButtonName"), - Description = _textService.Localize("healthcheck","seoRobotsRectifyDescription") - }); - } - - return - new HealthCheckStatus(message) - { - ResultType = success ? StatusResultType.Success : StatusResultType.Error, Actions = actions - }; - } - - private HealthCheckStatus AddDefaultRobotsTxtFile() - { - var success = false; - var message = string.Empty; - const string content = @"# robots.txt for Umbraco -User-agent: * -Disallow: /umbraco/"; - - try - { - File.WriteAllText(_hostingEnvironment.MapPathContentRoot("~/robots.txt"), content); - success = true; - } - catch (Exception exception) - { - _logger.LogError(exception, "Could not write robots.txt to the root of the site"); - } - - return - new HealthCheckStatus(message) - { - ResultType = success ? StatusResultType.Success : StatusResultType.Error, - Actions = new List() - }; - } -} -``` - -## Custom health check notifications - -Health check notifications can be scheduled to run periodically and notify you of the results. Included with Umbraco is a notification method to deliver the results via email. In a similar manner to how it's possible to create your health checks, you can also create custom notification methods. These methods can send the message summarizing the status of the health checks via other means. Again, for further details on implementing this please refer to the [existing notification methods within the core code base](https://github.com/umbraco/Umbraco-CMS/tree/v10/dev/src/Umbraco.Core/HealthChecks/NotificationMethods). - -Each notification method needs to implement the core interface `IHealthCheckNotificationMethod` and, for ease of creation, can inherit from the base class `NotificationMethodBase`, which itself implements the `IHealthCheckNotificationMethod` interface. The class must also be decorated with an instance of the `HealthCheckNotificationMethod` attribute. There's one method to implement - `SendAsync(HealthCheckResults results)`. This method is responsible for taking the results of the health checks and sending them via the mechanism of your choice. - -The following example shows how the core method for sending notification via email is implemented: - -```csharp -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Mail; -using Umbraco.Cms.Core.Models.Email; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Core.HealthChecks.NotificationMethods -{ - [HealthCheckNotificationMethod("email")] - public class EmailNotificationMethod : NotificationMethodBase - { - private readonly ILocalizedTextService? _textService; - private readonly IHostingEnvironment? _hostingEnvironment; - private readonly IEmailSender? _emailSender; - private readonly IMarkdownToHtmlConverter? _markdownToHtmlConverter; - private ContentSettings? _contentSettings; - - public EmailNotificationMethod( - ILocalizedTextService textService, - IHostingEnvironment hostingEnvironment, - IEmailSender emailSender, - IOptionsMonitor healthChecksSettings, - IOptionsMonitor contentSettings, - IMarkdownToHtmlConverter markdownToHtmlConverter) - : base(healthChecksSettings) - { - var recipientEmail = Settings?["RecipientEmail"]; - if (string.IsNullOrWhiteSpace(recipientEmail)) - { - Enabled = false; - return; - } - - RecipientEmail = recipientEmail; - - _textService = textService ?? throw new ArgumentNullException(nameof(textService)); - _hostingEnvironment = hostingEnvironment; - _emailSender = emailSender; - _markdownToHtmlConverter = markdownToHtmlConverter; - _contentSettings = contentSettings.CurrentValue ?? throw new ArgumentNullException(nameof(contentSettings)); - - contentSettings.OnChange(x => _contentSettings = x); - } - - public string? RecipientEmail { get; } - - public override async Task SendAsync(HealthCheckResults results) - { - if (ShouldSend(results) == false) - { - return; - } - - if (string.IsNullOrEmpty(RecipientEmail)) - { - return; - } - - var message = _textService?.Localize("healthcheck","scheduledHealthCheckEmailBody", new[] - { - DateTime.Now.ToShortDateString(), - DateTime.Now.ToShortTimeString(), - _markdownToHtmlConverter?.ToHtml(results, Verbosity) - }); - - // Include the Umbraco Application URL host in the message subject so that - // you can identify the site that these results are for. - var host = _hostingEnvironment?.ApplicationMainUrl?.ToString(); - - var subject = _textService?.Localize("healthcheck","scheduledHealthCheckEmailSubject", new[] { host }); - - - var mailMessage = CreateMailMessage(subject, message); - Task? task = _emailSender?.SendAsync(mailMessage, Constants.Web.EmailTypes.HealthCheck); - if (task is not null) - { - await task; - } - } - - private EmailMessage CreateMailMessage(string? subject, string? message) - { - var to = _contentSettings?.Notifications.Email; - - if (string.IsNullOrWhiteSpace(subject)) - subject = "Umbraco Health Check Status"; - - var isBodyHtml = message.IsNullOrWhiteSpace() == false && message!.Contains("<") && message.Contains(" options.SameOrigin()); - - ... - } -} -``` - -### Adding Click-Jacking Protection using manual middleware - -Avoid third-party library dependencies by using custom middleware added to the request pipeline. - -```csharp -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.Use(async (context, next) => - { - context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN"); - await next(); - }); - - ... - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/contentsniffingprotection.md b/10/umbraco-cms/extending/health-check/guides/contentsniffingprotection.md deleted file mode 100644 index 23e62295fba..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/contentsniffingprotection.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -description: Protect your Umbraco site from MIME sniffing vulnerabilities using security headers like X-Content-Type-Options. ---- - -# Health check: Content/MIME Sniffing Protection - -_Checks that your site contains a header used to protect against Multipurpose Internet Mail Extensions (MIME) sniffing vulnerabilities._ - -## How to fix this health check - -This health check can be fixed by adding a header before the response is started. - -Preferable you use a security library like [NWebSec](https://docs.nwebsec.com/). - -### Adding Content/MIME Sniffing Protection using NWebSec - -If you take a NuGet dependency on [NWebsec.AspNetCore.Middleware/](https://www.nuget.org/packages/NWebsec.AspNetCore.Middleware/), you can use third extension methods on `IApplicationBuilder`. - -```csharp -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.UseXContentTypeOptions(); - - ... - } -} -``` - -### Adding Content/MIME Sniffing Protection using manual middleware - -If you don't like to have a dependency on third party libraries. You can add the following custom middleware to the request pipeline. - -```csharp -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.Use(async (context, next) => - { - context.Response.Headers.Add("X-Content-Type-Options", "nosniff"); - await next(); - }); - - ... - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/crosssitescriptingprotection.md b/10/umbraco-cms/extending/health-check/guides/crosssitescriptingprotection.md deleted file mode 100644 index cc5f3a54152..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/crosssitescriptingprotection.md +++ /dev/null @@ -1,50 +0,0 @@ ---- - - ---- - -# Health check: Cross-site scripting Protection (X-XSS-Protection header) - -_This header enables the Cross-site scripting (XSS) filter in your browser. It checks for the presence of the X-XSS-Protection-header._ - -## How to fix this health check - -This health check can be fixed by adding a header before the response is started. - -Preferable you use a security library like [NWebSec](https://docs.nwebsec.com/). - -### Adding Cross-site scripting Protection using NWebSec - -If you take a NuGet dependency on [NWebsec.AspNetCore.Middleware/](https://www.nuget.org/packages/NWebsec.AspNetCore.Middleware/), you can use third extension methods on `IApplicationBuilder`. - -```csharp -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.UseXXssProtection(options => options.EnabledWithBlockMode()); - - ... - } -} -``` - -### Adding Cross-site scripting Protection using manual middleware - -If you don't like to have a dependency on third party libraries. You can add the following custom middleware to the request pipeline. - -```csharp -public class Startup -{ - public void Configure(IApplicationBuilder app) - { - app.Use(async (context, next) => - { - context.Response.Headers.Add("X-Xss-Protection", "1; mode=block"); - await next(); - }); - - ... - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/debugcompilationmode.md b/10/umbraco-cms/extending/health-check/guides/debugcompilationmode.md deleted file mode 100644 index 8395c9e09da..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/debugcompilationmode.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -description: Disable debug compilation mode in Umbraco to boost performance by updating JSON configuration. ---- - -# Health check: Debug Compilation Mode - -_Leaving debug compilation mode enabled can severely slow down a website and take up more memory on the server._ - -## How to fix this health check - -This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Hosting:Debug`. - -This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. - -### Updating the JSON configuration - -The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. - -```json -{ - "Umbraco": { - "CMS": { - "Hosting": { - "Debug": - } - } - } -} -``` - -One example that can be used for production: - -```json -{ - "Umbraco": { - "CMS": { - "Hosting": { - "Debug": false - } - } - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/excessiveheaders.md b/10/umbraco-cms/extending/health-check/guides/excessiveheaders.md deleted file mode 100644 index 83cc3458b42..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/excessiveheaders.md +++ /dev/null @@ -1,55 +0,0 @@ ---- - - ---- - -# Health check: Excessive Headers - -_Checks to see if your site is revealing information in its headers that gives away unnecessary details about the technology used to build and host it._ - -## How to fix this health check - -This health check can be fixed by removing headers before the response is started. - -Be aware these headers are often added by the server and not by the application. - -Unless you publicly expose the Kestrel server ([not recommended by Microsoft](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-2.1&tabs=aspnetcore2x#when-to-use-kestrel-with-a-reverse-proxy)), you can't handle this directly in middleware. - -### Removing headers when hosted on IIS - -For IIS you will need to manipulate `web.config` (If you don't have `web.config` already in your project you will need to add it at the root). Ensure to remove the custom `X-Powered-By` and `Server` header as shown in the following example. - -{% hint style="info" %} -The `removeServerHeader` attribute is added in IIS 10.0 and does not work in versions of Windows prior to Windows Server version 1709 or Windows 10 version 1709. -{% endhint %} - -```xml - - - - - - - - - - - - - -``` - -### Removing headers when hosted on Kestrel - -By default Kestrel will only expose the `Server` header. To disable this, you have to configure Kestrel in `Program.cs`. You can use the `UseKestrel` extension method on `IWebHostBuilder` like in the following example. - -```csharp -public class Program -{ - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup() - .UseKestrel(x => x.AddServerHeader = false); - }); -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/fixedapplicationurl.md b/10/umbraco-cms/extending/health-check/guides/fixedapplicationurl.md deleted file mode 100644 index c93944930bd..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/fixedapplicationurl.md +++ /dev/null @@ -1,43 +0,0 @@ -# Fixed Application Url - -_Check to make sure a fixed application URL is specified. This URL is for example used when sending emails from backoffice. If this is not specified in configuration, Umbraco gets the application URL from last host used to request the application_ - -## How to fix this health check - -This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:WebRouting:UmbracoApplicationUrl`. - -This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. - -### Updating the JSON configuration - -The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. - -```json -{ - "Umbraco": { - "CMS": { - "WebRouting": { - "UmbracoApplicationUrl": "string" - } - } - } -} -``` - -One example that can be used in production - -```json -{ - "Umbraco": { - "CMS": { - "WebRouting": { - "UmbracoApplicationUrl": "https://www.my-custom-domain.com/" - } - } - } -} -``` - -{% hint style="info" %} -If the site is hosted on Umbraco Cloud, changing the above configuration will have no effect. The site will always use the URL set in the\`umbraco-cloud.json\` file, which can not be changed. -{% endhint %} diff --git a/10/umbraco-cms/extending/health-check/guides/folderandfilepermissions.md b/10/umbraco-cms/extending/health-check/guides/folderandfilepermissions.md deleted file mode 100644 index 9a406dfbbbf..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/folderandfilepermissions.md +++ /dev/null @@ -1,25 +0,0 @@ -# Folder & File Permissions - -_Checks that the web server folder and file permissions are set correctly for Umbraco to run._ - -## How to fix this health check - -This health check can be fixed by ensuring that the process running Umbraco also has write access to the listed folders and files. - -### Updating the file permissions on Windows - -Here's an example of how to adjust permissions for a folder. This process works the same way for files. - -First we see an example of an error from the health check - -![Failed health check for folder creation]() - -To fix this, we find the specified folder, from the report and choose `Properties` and the `Security` tab. - -![Folder properties]() ![Folder properties - Security tab]() - -From here you can edit the permissions for a specific user or user group. - -{% hint style="info" %} -For security reasons we recommend only giving write access to the required users or groups. -{% endhint %} diff --git a/10/umbraco-cms/extending/health-check/guides/httpsconfiguration.md b/10/umbraco-cms/extending/health-check/guides/httpsconfiguration.md deleted file mode 100644 index e3fde2d9caf..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/httpsconfiguration.md +++ /dev/null @@ -1,48 +0,0 @@ ---- - - ---- - -# Health check: HTTPS Configuration - -_Checks if your site is configured to work over HTTPS and if the Umbraco related configuration for that is correct._ - -## How to fix this health check - -This health check checks a couple of things. - -First of all, it ensures that your website is running on HTTPS using a valid certificate. - -Furthermore, it is used to specify the configuration on the following path: `Umbraco:CMS:Global:UseHttps`. - -This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. - -### Updating the JSON configuration - -The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "UseHttps": - } - } - } -} -``` - -One example that can be used: - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "UseHttps": true - } - } - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions (1).png b/10/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions (1).png deleted file mode 100644 index 6dc15b3c5af..00000000000 Binary files a/10/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions.png b/10/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions.png deleted file mode 100644 index 6dc15b3c5af..00000000000 Binary files a/10/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions.png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/guides/images/folder_properties (1).png b/10/umbraco-cms/extending/health-check/guides/images/folder_properties (1).png deleted file mode 100644 index 871cf463060..00000000000 Binary files a/10/umbraco-cms/extending/health-check/guides/images/folder_properties (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/guides/images/folder_properties.png b/10/umbraco-cms/extending/health-check/guides/images/folder_properties.png deleted file mode 100644 index 871cf463060..00000000000 Binary files a/10/umbraco-cms/extending/health-check/guides/images/folder_properties.png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/guides/images/folder_properties_security (1).png b/10/umbraco-cms/extending/health-check/guides/images/folder_properties_security (1).png deleted file mode 100644 index 79a3fc7122e..00000000000 Binary files a/10/umbraco-cms/extending/health-check/guides/images/folder_properties_security (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/guides/images/folder_properties_security.png b/10/umbraco-cms/extending/health-check/guides/images/folder_properties_security.png deleted file mode 100644 index 79a3fc7122e..00000000000 Binary files a/10/umbraco-cms/extending/health-check/guides/images/folder_properties_security.png and /dev/null differ diff --git a/10/umbraco-cms/extending/health-check/guides/macroerrors.md b/10/umbraco-cms/extending/health-check/guides/macroerrors.md deleted file mode 100644 index 3782334f013..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/macroerrors.md +++ /dev/null @@ -1,44 +0,0 @@ ---- - - ---- - -# Health check: Macro errors - -_Checks to make sure macro errors are not set to throw a Yellow Screen Of Death (YSOD). This could prevent certain or all pages from loading._ - -## How to fix this health check - -This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Content:MacroErrors`. - -This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the json file sources. - -### Updating the json configuration - -The following json needs to be merged into one of you json sources. By default the following json sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. - -```json -{ - "Umbraco": { - "CMS": { - "Content": { - "MacroErrors": "" - } - } - } -} -``` - -One example that can be used in production, but is not recommended for development: - -```json -{ - "Umbraco": { - "CMS": { - "Content": { - "MacroErrors": "Silent" - } - } - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/notificationemail.md b/10/umbraco-cms/extending/health-check/guides/notificationemail.md deleted file mode 100644 index 51b9e66622a..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/notificationemail.md +++ /dev/null @@ -1,48 +0,0 @@ ---- - - ---- - -# Health check: Notification Email Settings - -_If notifications are used, the 'from' email address should be specified and changed from the default value._ - -## How to fix this health check - -This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Content:Notifications:Email`. - -This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. - -### Updating the JSON configuration - -The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. - -```json -{ - "Umbraco": { - "CMS": { - "Content": { - "Notifications": { - "Email": "" - } - } - } - } -} -``` - -One example that can be used: - -```json -{ - "Umbraco": { - "CMS": { - "Content": { - "Notifications": { - "Email": "no-reply@domain.com" - } - } - } - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/smtp.md b/10/umbraco-cms/extending/health-check/guides/smtp.md deleted file mode 100644 index 37a2fda072e..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/smtp.md +++ /dev/null @@ -1,57 +0,0 @@ ---- - - ---- - -# Health check: SMTP - -_Checks that valid settings for sending emails are in place._ - -## How to fix this health check - -This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Global:Smtp` - -This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. - -### Updating the JSON configuration - -The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "Smtp": { - "From": "", - "Host": "", - "Port": "", - "PickupDirectoryLocation": "", - "Username": "", - "Password": "", - "DeliveryMethod": "", - "SecureSocketOptions": "" - } - } - } - } -} -``` - -An example that can be used on localhost, is if you have a local Simple Mail Transfer Protocol (SMTP) server running during development. This could be a tool like [Smtp4dev](https://github.com/rnwood/smtp4dev). - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "Smtp": { - "From": "my@email.com", - "Host": "localhost", - "Port": "25" - } - } - } - } -} -``` diff --git a/10/umbraco-cms/extending/health-check/guides/stricttransportsecurityheader.md b/10/umbraco-cms/extending/health-check/guides/stricttransportsecurityheader.md deleted file mode 100644 index 08907fa69ca..00000000000 --- a/10/umbraco-cms/extending/health-check/guides/stricttransportsecurityheader.md +++ /dev/null @@ -1,38 +0,0 @@ ---- - - ---- - -# Health check: Cookie hijacking and protocol downgrade attacks Protection (Strict-Transport-Security Header (HSTS)) - -_Checks if your site, when running with HTTPS, contains the Strict-Transport-Security Header (HSTS)._ - -## How to fix this health check - -This health check can be fixed by adding the `Strict-Transport-Security` header to responses. The header tells browsers that future requests should be made over HTTPS only. - -{% hint style="warning" %} -Enabling HSTS on a domain will cause browsers to only use HTTPS (not HTTP) to communicate with your site. Only enable HSTS on domains that can, and should, use HTTPS exclusively. -{% endhint %} - -### Using the UseHsts extension method -ASP.NET Core implements HSTS with the `UseHsts` extension method. - -You can add `UseHsts` after the `env.IsDevelopment()` check in `Startup.cs`. -```csharp -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseHsts(); - } - //... -} -``` -This example only enables HSTS if the app is not running in development mode. `UseHsts` isn't recommended in development because the HSTS settings are highly cacheable by browsers. - -Full details of `UseHsts`, and additional configuration, can be found in the [ASP.NET Core documentation](https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-5.0&tabs=visual-studio#http-strict-transport-security-protocol-hsts-1). diff --git a/10/umbraco-cms/extending/images/Canvas_tab (1) (1).png b/10/umbraco-cms/extending/images/Canvas_tab (1) (1).png deleted file mode 100644 index 1e6b0c0730a..00000000000 Binary files a/10/umbraco-cms/extending/images/Canvas_tab (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Canvas_tab (1) (2).png b/10/umbraco-cms/extending/images/Canvas_tab (1) (2).png deleted file mode 100644 index 1e6b0c0730a..00000000000 Binary files a/10/umbraco-cms/extending/images/Canvas_tab (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Canvas_tab (1).png b/10/umbraco-cms/extending/images/Canvas_tab (1).png deleted file mode 100644 index 1e6b0c0730a..00000000000 Binary files a/10/umbraco-cms/extending/images/Canvas_tab (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Canvas_tab.png b/10/umbraco-cms/extending/images/Canvas_tab.png deleted file mode 100644 index 1e6b0c0730a..00000000000 Binary files a/10/umbraco-cms/extending/images/Canvas_tab.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Docs_tab (1) (1).png b/10/umbraco-cms/extending/images/Docs_tab (1) (1).png deleted file mode 100644 index ac21325f172..00000000000 Binary files a/10/umbraco-cms/extending/images/Docs_tab (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Docs_tab (1) (2).png b/10/umbraco-cms/extending/images/Docs_tab (1) (2).png deleted file mode 100644 index ac21325f172..00000000000 Binary files a/10/umbraco-cms/extending/images/Docs_tab (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Docs_tab (1).png b/10/umbraco-cms/extending/images/Docs_tab (1).png deleted file mode 100644 index ac21325f172..00000000000 Binary files a/10/umbraco-cms/extending/images/Docs_tab (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Docs_tab.png b/10/umbraco-cms/extending/images/Docs_tab.png deleted file mode 100644 index ac21325f172..00000000000 Binary files a/10/umbraco-cms/extending/images/Docs_tab.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Embed-Button.png b/10/umbraco-cms/extending/images/Embed-Button.png deleted file mode 100644 index 4c93e5ba89b..00000000000 Binary files a/10/umbraco-cms/extending/images/Embed-Button.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/Embed-YouTube.png b/10/umbraco-cms/extending/images/Embed-YouTube.png deleted file mode 100644 index fe620025758..00000000000 Binary files a/10/umbraco-cms/extending/images/Embed-YouTube.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/content-app-1.png b/10/umbraco-cms/extending/images/content-app-1.png deleted file mode 100644 index ffae7300253..00000000000 Binary files a/10/umbraco-cms/extending/images/content-app-1.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/content-app-2.png b/10/umbraco-cms/extending/images/content-app-2.png deleted file mode 100644 index b3b479c6c3c..00000000000 Binary files a/10/umbraco-cms/extending/images/content-app-2.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/content-app-badge-v9.png b/10/umbraco-cms/extending/images/content-app-badge-v9.png deleted file mode 100644 index 7afd0e57dc3..00000000000 Binary files a/10/umbraco-cms/extending/images/content-app-badge-v9.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/content-app-badge.png b/10/umbraco-cms/extending/images/content-app-badge.png deleted file mode 100644 index 80d3b00631e..00000000000 Binary files a/10/umbraco-cms/extending/images/content-app-badge.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/content-apps-location.png b/10/umbraco-cms/extending/images/content-apps-location.png deleted file mode 100644 index 7192d228876..00000000000 Binary files a/10/umbraco-cms/extending/images/content-apps-location.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/content-dashboards.png b/10/umbraco-cms/extending/images/content-dashboards.png deleted file mode 100644 index f2ef027c2e8..00000000000 Binary files a/10/umbraco-cms/extending/images/content-dashboards.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1) (1).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1) (1).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1) (2).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1) (2).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (2).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (2).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (3).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (3).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (2).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (2).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (1).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (1).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (2) (1).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (2) (1).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (2) (2).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (2) (2).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1) (2).png b/10/umbraco-cms/extending/images/contentTypespecific (1) (2).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (1).png b/10/umbraco-cms/extending/images/contentTypespecific (1).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific (2).png b/10/umbraco-cms/extending/images/contentTypespecific (2).png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific-v8.png b/10/umbraco-cms/extending/images/contentTypespecific-v8.png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/contentTypespecific.png b/10/umbraco-cms/extending/images/contentTypespecific.png deleted file mode 100644 index 06cfabb8035..00000000000 Binary files a/10/umbraco-cms/extending/images/contentTypespecific.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1) (1) (1).png b/10/umbraco-cms/extending/images/db-table (1) (1) (1).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1) (1) (2).png b/10/umbraco-cms/extending/images/db-table (1) (1) (2).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1) (1).png b/10/umbraco-cms/extending/images/db-table (1) (1).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1) (2).png b/10/umbraco-cms/extending/images/db-table (1) (2).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1) (3).png b/10/umbraco-cms/extending/images/db-table (1) (3).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1) (4).png b/10/umbraco-cms/extending/images/db-table (1) (4).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1) (4).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (1).png b/10/umbraco-cms/extending/images/db-table (1).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (2) (1).png b/10/umbraco-cms/extending/images/db-table (2) (1).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (2) (2).png b/10/umbraco-cms/extending/images/db-table (2) (2).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (2) (3).png b/10/umbraco-cms/extending/images/db-table (2) (3).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (2) (3).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (2) (4).png b/10/umbraco-cms/extending/images/db-table (2) (4).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (2) (4).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table (2).png b/10/umbraco-cms/extending/images/db-table (2).png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table (2).png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/db-table.png b/10/umbraco-cms/extending/images/db-table.png deleted file mode 100644 index f5bae665216..00000000000 Binary files a/10/umbraco-cms/extending/images/db-table.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/developer-dashboards.png b/10/umbraco-cms/extending/images/developer-dashboards.png deleted file mode 100644 index 1304c5c1805..00000000000 Binary files a/10/umbraco-cms/extending/images/developer-dashboards.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/deviantart-embedded-media.png b/10/umbraco-cms/extending/images/deviantart-embedded-media.png deleted file mode 100644 index ca8a8902ac1..00000000000 Binary files a/10/umbraco-cms/extending/images/deviantart-embedded-media.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/element-v8.png b/10/umbraco-cms/extending/images/element-v8.png deleted file mode 100644 index 878ce70c25b..00000000000 Binary files a/10/umbraco-cms/extending/images/element-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/element.png b/10/umbraco-cms/extending/images/element.png deleted file mode 100644 index 75bdeea01cc..00000000000 Binary files a/10/umbraco-cms/extending/images/element.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/image-position-v8.png b/10/umbraco-cms/extending/images/image-position-v8.png deleted file mode 100644 index 7a9995081f5..00000000000 Binary files a/10/umbraco-cms/extending/images/image-position-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/image-position.png b/10/umbraco-cms/extending/images/image-position.png deleted file mode 100644 index f6b86300305..00000000000 Binary files a/10/umbraco-cms/extending/images/image-position.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/introstep.png b/10/umbraco-cms/extending/images/introstep.png deleted file mode 100644 index ca631766a82..00000000000 Binary files a/10/umbraco-cms/extending/images/introstep.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/step-event-element-v8.png b/10/umbraco-cms/extending/images/step-event-element-v8.png deleted file mode 100644 index 185991d1530..00000000000 Binary files a/10/umbraco-cms/extending/images/step-event-element-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/step-event-element.png b/10/umbraco-cms/extending/images/step-event-element.png deleted file mode 100644 index fb12fee4e39..00000000000 Binary files a/10/umbraco-cms/extending/images/step-event-element.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/stepcontent-v8.png b/10/umbraco-cms/extending/images/stepcontent-v8.png deleted file mode 100644 index cf0776b57d0..00000000000 Binary files a/10/umbraco-cms/extending/images/stepcontent-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/stepcontent.png b/10/umbraco-cms/extending/images/stepcontent.png deleted file mode 100644 index adbe84d994a..00000000000 Binary files a/10/umbraco-cms/extending/images/stepcontent.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/steptitle-v8.png b/10/umbraco-cms/extending/images/steptitle-v8.png deleted file mode 100644 index 522e3008c1a..00000000000 Binary files a/10/umbraco-cms/extending/images/steptitle-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/steptitle.png b/10/umbraco-cms/extending/images/steptitle.png deleted file mode 100644 index c3ea636c953..00000000000 Binary files a/10/umbraco-cms/extending/images/steptitle.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/the-dashboard-package.png b/10/umbraco-cms/extending/images/the-dashboard-package.png deleted file mode 100644 index e565eea3cf4..00000000000 Binary files a/10/umbraco-cms/extending/images/the-dashboard-package.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/tourallowdisable-v8.png b/10/umbraco-cms/extending/images/tourallowdisable-v8.png deleted file mode 100644 index ba501f4fd87..00000000000 Binary files a/10/umbraco-cms/extending/images/tourallowdisable-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/tourallowdisable.png b/10/umbraco-cms/extending/images/tourallowdisable.png deleted file mode 100644 index 7d24eae70e6..00000000000 Binary files a/10/umbraco-cms/extending/images/tourallowdisable.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/tourgroup-v8.png b/10/umbraco-cms/extending/images/tourgroup-v8.png deleted file mode 100644 index b2a4a7efb38..00000000000 Binary files a/10/umbraco-cms/extending/images/tourgroup-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/tourgroup.png b/10/umbraco-cms/extending/images/tourgroup.png deleted file mode 100644 index 2509c199dba..00000000000 Binary files a/10/umbraco-cms/extending/images/tourgroup.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/tourname-v8.png b/10/umbraco-cms/extending/images/tourname-v8.png deleted file mode 100644 index e247687d244..00000000000 Binary files a/10/umbraco-cms/extending/images/tourname-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/tourname.png b/10/umbraco-cms/extending/images/tourname.png deleted file mode 100644 index 91466067eb7..00000000000 Binary files a/10/umbraco-cms/extending/images/tourname.png and /dev/null differ diff --git a/10/umbraco-cms/extending/images/welcome-example.png b/10/umbraco-cms/extending/images/welcome-example.png deleted file mode 100644 index 295c6932441..00000000000 Binary files a/10/umbraco-cms/extending/images/welcome-example.png and /dev/null differ diff --git a/10/umbraco-cms/extending/key-vault.md b/10/umbraco-cms/extending/key-vault.md deleted file mode 100644 index 5e396362ffb..00000000000 --- a/10/umbraco-cms/extending/key-vault.md +++ /dev/null @@ -1,237 +0,0 @@ ---- - -meta.Title: Azure Key Vault -description: A guide for configuring Azure Key Vault ---- - -# Configuring Azure Key Vault - -From a security perspective, storing your application secrets in Azure Key Vault is always a good solution. This could be a connection string or other keys. - -This article tells you how to configure your application so it is ready to use a Key Vault. - -Depending on your hosting situation there are a few approaches to incorporating Azure Key Vault into your application. - -1. [Install Key Vault via Nuget (for most Hosting scenarios)](key-vault.md#install-key-vault-via-nuget) -2. [Use Key Vault references for Azure App Service (For Azure Web App Hosting) ](key-vault.md#use-key-vault-references-for-azure-app-service) - -## Install Key Vault via Nuget - -Before you begin, you need to install the `Azure.Extensions.AspNetCore.Configuration.Secrets` and the `Azure.Identity` NuGet packages. There are two approaches to installing the packages: - -1. Use your favorite Integrated Development Environment (IDE) and open up the NuGet Package Manager to search and install the packages -2. Use the command line to install the package - -### Installing through command line - -Navigate to your project folder, which is the folder that contains your `.csproj` file. Now use the following `dotnet add package` command to install the packages: - -``` -dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets -dotnet add package Azure.Identity -``` - -### Configuration - -{% hint style="info" %} -You can find the database connection string under the `Umbraco:CMS:ConnectionStrings` section in the `appsettings.json` file. For more information, see the [Connection strings settings](../reference/configuration/connectionstringssettings.md) article. -{% endhint %} - -The next step is to add the Azure Key Vault endpoint to the `appsettings.json` file (or create as an Environment Variable). You can add this endpoint in the root or anywhere in the `appsettings.json` as long as it is resolved in the `ConfigureAppConfiguration` method. - -```json -{ - "AzureKeyVaultEndpoint": "https://{your-key-vault-name}.vault.azure.net", -} -``` - -After adding the Key Vault endpoint you have to update the `CreateHostBuilder` method which you can find in the `Program.cs` file. - -{% tabs %} -{% tab title="Latest version" %} -```csharp -public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureUmbracoDefaults() - .ConfigureAppConfiguration((context, config) => - { - var settings = config.Build(); - var keyVaultEndpoint = settings["AzureKeyVaultEndpoint"]; - if (!string.IsNullOrEmpty(keyVaultEndpoint) && Uri.TryCreate(keyVaultEndpoint, UriKind.Absolute, out var validUri)) - { - config.AddAzureKeyVault(validUri, new DefaultAzureCredential()); - } - }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStaticWebAssets(); - webBuilder.UseStartup(); - }); -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureLogging(x => x.ClearProviders()) - .ConfigureAppConfiguration((context, config) => - { - var settings = config.Build(); - var keyVaultEndpoint = settings["AzureKeyVaultEndpoint"]; - if (!string.IsNullOrWhiteSpace(keyVaultEndpoint)) - { - if (!string.IsNullOrWhiteSpace(keyVaultEndpoint) && Uri.TryCreate(keyVaultEndpoint, UriKind.Absolute, out var validUri)) - { - config.AddAzureKeyVault(validUri, new DefaultAzureCredential()); - } - } - }) - .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); -``` -{% endtab %} -{% endtabs %} - -### Authentication - -There are different ways to access the Azure Key Vault. It is important that the user you are logging in with has access to the Key Vault. You can assign roles using the Azure Portal. - -1. Navigate to your Key Vault. -2. Select Access Control. -3. Select Add -> Add role assignment. -4. Select the preferred role. -5. Search for the user. -6. Click review + assign - -## Use Key Vault references for Azure App Service - -Azure Web Apps offers the ability to directly reference Key Vault secrets as App Settings. The benefit of this is you can securely store your secrets in Key Vault without any code changes required in your application. - -### Create a System Assigned Managed Identity - -To begin we first need to create a **Managed Identity** for the Azure Web App. This enables us to grant granular permissions to an identity representing the Web App. - -Head over to your Azure Web App and find **Identity** under **Settings**: - -![image](https://user-images.githubusercontent.com/11179749/196052374-cebcfbc3-848f-4866-8e0f-70a57e776f60.png) - -Under **System assigned** change the Status from Off to **On**. - -![image](https://user-images.githubusercontent.com/11179749/196052406-2205c1bc-504a-41be-86bf-81b1cabbc17f.png) - -A GUID will then be generated called **Object (principal) ID**. Take note of this ID as we will need it further on. - -### Update your Key Vault Access Policy - -It is assumed you already have a Key Vault set up with a few Umbraco secrets inside. In your Key Vault head to **Access Policies**. - -![image](https://user-images.githubusercontent.com/11179749/196052540-e1368016-ad7a-4b69-b05c-2875a4f11998.png) - -At the top select **+ Create**. We are now going to add the **System Managed Identity** for the Web App to Key Vault. - -![image](https://user-images.githubusercontent.com/11179749/196052612-e3b2041c-785f-46f5-b9b5-d8ad33b893ac.png) - -You will now be presented with different permissions to set for your Web App. You only need **Get** and **List** for **Secret Permissions** only. Click **Next** to continue: - -![image](https://user-images.githubusercontent.com/11179749/196052668-124d1496-4486-4098-9198-eff809876c80.png) - -Enter the GUID you took note of earlier, into the **Search Box**. You will see your Web App listed. - -![image](https://user-images.githubusercontent.com/11179749/196052706-15431bf4-80ea-4bb7-b40e-ebda45264fb7.png) - -Click your Web App to Select and click Next and then Create: - -![image](https://user-images.githubusercontent.com/11179749/196052849-970a97c5-e945-415a-9469-a67f485424ea.png) - -If you visit the **Access Policies** section again you should now see your web app in the list and its permissions: - -![image](https://user-images.githubusercontent.com/11179749/196052924-0d0559c0-a414-4bbd-ab91-94fc25dc720f.png) - -### Link our Key Vault Secret to an Azure Web App - -In your Azure Web App head to **Configuration** under **Settings**. - -![image](https://user-images.githubusercontent.com/11179749/196053006-3a95fc5f-1038-4228-9ae4-467050ea5759.png) - -Here we can add our **App Settings** and **Connection Strings** to the environment. - -1. Let us start off with the **Umbraco Database Connection String**. - -Under Connection Strings, select **Advanced Edit**. - -![image](https://user-images.githubusercontent.com/11179749/196053130-8fb6c2b9-61c7-4c02-a419-8570174c6646.png) - -Once you click on "**Advanced Edit"** a new window will open up. There you will need to paste in the following JSON Object inside the square brackets. Ensure you update `{keyvault-name}`, `{secret-name}` and `{version-id}`. - -```json -{ - "name": "umbracoDbDSN", - "value": "@Microsoft.KeyVault(SecretUri=https://{keyvault-name}.vault.azure.net/secrets/{secret-name}/{version-id}/)", - "type": "Custom", - "slotSetting": false -} -``` - -{% hint style="info" %} -You can obtain the Secret Uri by visiting the specific version of your secret and copying the Url: -{% endhint %} - -![image](https://user-images.githubusercontent.com/11179749/196054001-cc215c04-d29c-435a-ae7b-6e8efb7f3faa.png) - -The ID is optional but recommended as it enables you to control which version of the secret is used at your discretion. Leave it out if you always want the Web App to pull the latest version of the secret. - -Wait a moment and refresh the screen. You should see a Green tick. If you do not have a Green tick you need to review your Access Policies in the previous step. - -![image](https://user-images.githubusercontent.com/11179749/196053419-f53feba2-b8ed-4b98-99f0-ee68f58ac8e4.png) - -2. We will perform the same approach for our **App Settings**. We will be updating the following App Settings for Azure Blob Storage. - -```json -"Umbraco": { - "Storage": { - "AzureBlob": { - "Media": { - "ConnectionString": "", - "ContainerName": "" - } - } - } -``` - -Due to the secrets being nested we need to use double underscore `__` to correctly reference the value on our Web App. - -On the Web App select **Advanced Edit** for Application Settings: - -

Application setting

- -When clicking on "Advanced Edit", a new window will open up. There you will need to paste in the following JSON Objects inside the square brackets. Ensure you update `{keyvault-name}`, `{secret-name}` and `{version-id}`. - -```json -{ - "name": "Umbraco__Storage__AzureBlob__Media__ConnectionString", - "value": "@Microsoft.KeyVault(SecretUri=https://{keyvault-name}.vault.azure.net/secrets/{secret-name}/{version-id}/)", - "slotSetting": false -}, -{ - "name": "Umbraco__Storage__AzureBlob__Media__ContainerName", - "value": "@Microsoft.KeyVault(SecretUri=https://{keyvault-name}.vault.azure.net/secrets/{secret-name}/{version-id}/)", - "slotSetting": false -} -``` - -The ID is optional but recommended as it enables you to control which version of the secret is used at your discretion. Leave it out if you always want the Web App to pull the latest version of the secret. - -Wait a moment and refresh the screen. You should see Green ticks for both values. If you do not have a Green tick you need to review your Access Policies in the previous step. - -
- -### Local Development - -1. [Sign in to Visual Studio using the credentials that can access the Key Vault.](https://docs.microsoft.com/en-us/visualstudio/ide/signing-in-to-visual-studio) -2. [Use Azure CLI to store your preferred account into the credential cache.](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli) - -### Staging/Production - -1. [Managed identities for Azure resources](https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-6.0#use-managed-identities-for-azure-resources) -2. [X.509 certificate for non-Azure-hosted apps](https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-6.0#use-application-id-and-x509-certificate-for-non-azure-hosted-apps) -3. [Use Key Vault references for App Service and Azure Functions](https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references) diff --git a/10/umbraco-cms/extending/language-files.md b/10/umbraco-cms/extending/language-files.md deleted file mode 100644 index 87afba5030d..00000000000 --- a/10/umbraco-cms/extending/language-files.md +++ /dev/null @@ -1,197 +0,0 @@ ---- -meta.Title: Language Files & Localization -description: >- - Language files are used to translate the Umbraco backoffice user interface so - that end users can use Umbraco in their native language. ---- - -# Language Files & Localization - -Language files are XML files used to translate: - -* The Umbraco backoffice user interface so that end users can use Umbraco in their native language. This is particularly important for content editors who do not speak English. -* The member identity errors in an Umbraco website enabling end users to use Umbraco in the website language. -* Read [Add translations for your packages](packages/language-files-for-packages.md) to see how to include translations for your own package. -* Override existing language files - -This is an example of such a language file, the most important parts are the `alias` fields of the `` and `` elements. This is what you need to retrieve the values from .NET or Angular. - -```xml - - - - The Umbraco community - https://community.umbraco.com/ - - - Culture and Hostnames - Audit Trail - - - Save - Cancel - - ... - -``` - -## Supported Languages - -Current languages that are included in the core are: - -* English (UK) -* English (US) -* Danish -* German -* Spanish -* French -* Hebrew (Israel) -* Italian -* Japanese -* Korean -* Dutch -* Norwegian -* Polish -* Portuguese -* Russian -* Swedish -* Chinese -* Chinese (Taiwan) -* Czech -* Turkish -* Welsh - -## Where to find the language files - -### Core language files - -The core Umbraco language files are found at the following location within the Umbraco source: - -```xml -Umbraco-CMS/src/Umbraco.Core/EmbeddedResources/Lang/ -``` - -These language files are the ones shipped with Umbraco and should not be modified. - -### Package language files - -If you are a package developer, [see here for docs on how to include translations for your own package](packages/language-files-for-packages.md), package language files are located in: - -```xml -/App_Plugins/mypackage/Lang/{language}.xml -``` - -{% hint style="info" %} -The `App_Plugins` version of the `Lang` directory is case sensitive on Linux systems, so make sure that it start with a capital `L`. -{% endhint %} - -### User language files - -If you want to override Umbraco core translations or translations shipped with packages, you can do that too, these files are located here: - -```xml -/config/lang/{language}.user.xml -``` - -{% hint style="info" %} -The `/config/lang/` folders do not exist on a clean installation of the CMS. You will need to create them at the root of your `src` project. -{% endhint %} - -By default, these files are empty but you can add any new keys you want or override existing ones with your own translations. The nice part about the user files is that they will not get overwritten by the installer when you upgrade your Umbraco versions. - -In order for these files to deploy when you do a `dotnet publish`, you need to add the following to your `.csproj` file: - -```xml - - - -``` - -## Using the language keys - -Using core or custom language keys from your code: - -### From .NET - -`ILocalizedTextService` is used to localize strings, and is available through dependency injection. First, inject the service, and then use the `Localize()` method available in the namespace `Umbraco.Extensions` to localize the string with the format `\[area]/\[key]`: - -```csharp -public MyClass(ILocalizedTextService textservice) -{ - var localizedLabel = textservice.Localize("dialog/mykey"); -} -``` - -### From Angular - -In the Umbraco backoffice UI, labels can be localized with the `localize` directive. The syntax is slightly different when compared to the .NET variant. Here the syntax is `\[area]_\[key]`: - -```xml - -``` - -The localize directive can also be used as an attribute like below. The value of the title attribute is then populated with the dictionary key "title\_name" from the language file using "@title\_name". - -```xml - -``` - -Or from a controller by using the `LocalizationService` which returns an async translation in a promise: - -```javascript -localizationService.localize("dialog_myKey").then(function(value){ - element.html(value); -}); -``` - -## Help keep the language files up to date - -As Umbraco is a continually evolving product it is inevitable that new text is added regularly to the English language version of these files. This may mean that some of the above languages are no longer up to date. - -If a translation is missing, the key "alias" used will be shown within the user interface, as an example: - -```xml -[assignDomain] -``` - -The language files are XML files with a straight-forward layout as seen below. - -```xml - - - - The Umbraco community - https://our.umbraco.com - - - Culture and Hostnames - Audit Trail - ... - - ... - -``` - -In the above example of a missing translation for "assignDomain", locate this string in the en.xml file. Then copy the whole "Key" element into the relevant language file. Then you can translate the text, as an example here is the Spanish version of the above snippet: - -```xml - - - - The Umbraco community - https://our.umbraco.com - - - Administrar hostnames - Auditoría - ... - - ... - -``` - -If you modify core language files or introduce a new language, you can assist the community by sharing your updates. This can be done by [submitting a pull request](https://github.com/umbraco/Umbraco-CMS/blob/main/.github/CONTRIBUTING.md) so that your changes are merged into the core. diff --git a/10/umbraco-cms/extending/macro-parameter-editors.md b/10/umbraco-cms/extending/macro-parameter-editors.md deleted file mode 100644 index c89bcf06dda..00000000000 --- a/10/umbraco-cms/extending/macro-parameter-editors.md +++ /dev/null @@ -1,220 +0,0 @@ ---- -meta.Title: Macro Parameter Editors -description: A guide to creating macro property editors in Umbraco ---- - -# Macro Parameter Editors - -{% hint style="info" %} -The samples in this article has not been verified against the latest version of Umbraco. -{% endhint %} - -Every macro can contain parameters. Options for the Editor to set when they insert the Macro to customise the output. There are some useful default types. For example: - -* True/False -* TextBox -* TextArea -* Numeric -* Single/Multiple Media Picker -* Single/Multiple Content Picker -* ... and some 'others' - -Consult the [Backoffice documentation](../fundamentals/backoffice/) for general information on Macros. - -It is possible to create custom macro parameter types. - -## Creating a custom Macro Parameter Type - -### isParameterEditor - -To create a custom Macro Parameter Type, first create a custom 'Property Editor' (or copy one from the core). See [Property Editors documentation](property-editors/) and in the corresponding [Package Manifest file](property-editors/package-manifest.md) for the editor, set the `isParameterEditor` property to be true. - -```json -{ - "propertyEditors": [ - { - "alias": "My.ParameterEditorAlias", - "name": "Parameter Editor Name", - "isParameterEditor": true, - "editor": { - "view": "/App_Plugins/My.ParameterEditor/ParameterEditorView.html" - } - } - ] -} -``` - -### PreValues/Configuration/DefaultValues - -'Parameter Editors', unlike 'Property Editors', cannot contain 'prevalues'. This is because there is no UI to present configuration options in the Macro Parameter tab when a particular type is chosen. However using the `defaultConfig` option enables the passing of 'one off' default set of configuration for the parameter editor to use: - -```json -{ - "propertyEditors": [ - { - "alias": "My.ParameterEditorAlias", - ... - "defaultConfig": { - "startNode": "1234", - "minItems": 0, - "maxItems": 6 - } - } - ] -} -``` - -This is only a problem if you have a macro parameter type that needs to be used on lots of different macros. Each instance may require slightly different configurations. - -### Example - -We'll create an 'Image Position' Macro Parameter type, providing a Radio Button list of options for positioning an image. This image is inserted via an 'Insert Image' Macro into a Rich Text Editor. - -#### Package Manifest - -```json -{ - "propertyEditors": [ - { - "alias": "Our.Umbraco.ImagePosition", - "name": "Image Position", - "isParameterEditor": true, - "editor": { - "view": "/App_Plugins/Our.Umbraco.ImagePosition/ImagePosition.html", - "valueType": "STRING" - } - } - ], - "javascript": [ - "/App_Plugins/Our.Umbraco.ImagePosition/ImagePosition.controller.js" - ] -} -``` - -#### View - -```html -
-
- -
-
-``` - -#### Controller - -```javascript -angular.module("umbraco").controller("Our.Umbraco.ImagePositionController", function ($scope) { - - if ($scope.model.value == null) { - $scope.model.value = 'FullWidth'; - } - - // could read positions from defaultConfig - $scope.positions = [ - { - Name: 'FullWidth' - }, - { - Name: 'Left' - }, - { - Name: 'Right' - }, - { - Name: 'Center' - } - ]; -}); -``` - -#### Display - -The final custom parameter should look like this: - -![Image Position Radio Button Options](images/image-position-v8.png) - -#### Using defaultConfig - -In this example, moving the radio button options into configuration doesn't really add anything. However, to illustrate the concept of providing defaultConfig, let's do that: - -The package manifest becomes: - -```json -{ - "propertyEditors": [ - { - "alias": "Our.Umbraco.ImagePosition", - "name": "Image Position", - "isParameterEditor": true, - "editor": { - "view": "/App_Plugins/Our.Umbraco.ImagePosition/ImagePosition.html", - "valueType": "STRING" - }, - "prevalues": { - "fields": [ - { - "label": "Options", - "description": "Radio Button Options", - "key": "options", - "view": "textarea" - } - ] - }, - "defaultConfig": { - "options": [ - { - "Name": "FullWidth" - }, - { - "Name": "Lefty" - }, - { - "Name": "Righty" - }, - { - "Name": "Centerish" - } - ] - } - } - ], - "javascript": [ - "/App_Plugins/Our.Umbraco.ImagePosition/ImagePosition.controller.js" - ] -} -``` - -In the `ImagePosition.controller.js` we can now read the 'options' values from the `defaultConfig` in the package.manifest configuration: - -```javascript - $scope.positions = $scope.model.config.options; -``` - -### Reading the parameter value in the Macro Partial View - -```csharp -@using Umbraco.Extensions -@inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage -@{ -var imagePosition = Model.MacroParameters["imagePosition"]; -//or if for convenience if you are using Umbraco.Extensions namespace there is a GetParameterValue extension method, which allows a default value to be specified if the parameter is not provided: -imagePosition = Model.GetParameterValue("imagePosition","full-width"); -} -``` - -### Runtime minification cache busting in Production - -If your custom property editor doesn't load when your project is deployed, you may need to modify your [Runtime Minification Settings](../reference/configuration/runtimeminificationsettings.md). The minified bundle cache may need to be "busted" to get your new code to load. For example, to bust the cache whenever the app is restarted, you can use this configuration: - -```json -"Umbraco": { - "CMS": { - "RuntimeMinification": { - "CacheBuster": "AppDomain" - } - } -} -``` diff --git a/10/umbraco-cms/extending/packages/README.md b/10/umbraco-cms/extending/packages/README.md deleted file mode 100644 index 392e6976644..00000000000 --- a/10/umbraco-cms/extending/packages/README.md +++ /dev/null @@ -1,79 +0,0 @@ ---- - -meta.Title: "Umbraco Packages" -description: "A package extends the functionality of Umbraco to provide additional functionality to editors, developers, site visitors, and all other types of users of Umbraco." ---- - -# Packages - -## What is a Package? - -A package extends Umbraco to provide additional functionality to editors, developers, site visitors, and all other types of users of Umbraco. It can impact one or more of these groups of people depending on the type of package. - -An Umbraco Package can be many things, but is generally characterized by: - -- Adding or extending functionality in the Umbraco CMS -- Empowering people to do more and/or do things more efficiently -- Engaging community members in collaboration and sharing -- Solving real life problems -- Inspiring people on what Umbraco can be made capable of - -### Categories of packages - -Packages provide a wide variety of functionality, and can often span multiple categories. In general, though, the functionality they provide fall into these main groups: - -- [Schema Extensions](#schema-extensions) -- [Management Extensions](#management-extensions) -- [Starter Kits](#starter-kits) -- [Content Apps](#content-apps) -- [Integration Extensions](#integration-extensions) - -#### Schema Extensions - -A package that can be categorized as a Schema Extension will extend the default Umbraco Schema. Schema in this sense refers to things like Data Types, Property Editors, Document Types and Media Types. By extending Umbraco with packages such as [Umbraco Commerce](https://docs.umbraco.com/umbraco-commerce) editors are given greater capabilities when they are populating their content pages. - -#### Management Extensions - -A Management Extension package helps you manage your site, and provides information to the users. Management extensions typically contain custom sections or dashboards to facilitate site management. [Diplo God Mode](https://marketplace.umbraco.com/package/diplo.godmode) is an example of a comprehensive management extension package with additional tools and information. - -#### Starter Kits - -Starter kits are, as the name suggests, a package that helps you set up a starter version of whatever you want to build. Most starter kit packages are for starting a website, and include schema like Document Types and Templates as well as content nodes and media. There are also some specialized starter kits, for example for creating a blog. Umbraco HQ has released their [own starter kit](https://www.nuget.org/packages/Umbraco.TheStarterKit), that creates a small site with the most commonly used features. - -#### Content Apps - -Content apps are almost like dashboards for content nodes that are intended to display node specific information. A good example of this is the [Preflight](https://marketplace.umbraco.com/package/preflight.umbraco) content app. It shows you readability scores for your written content, directly on each content node. - -#### Integration extensions - -This type of package can be a lot of things, and can include a number of the other package types. They are generally integrating a larger system into Umbraco. A good example could be an e-commerce package such as [UCommerce](https://marketplace.umbraco.com/package/ucommerce.umbraco8), that includes an entire webshop module for Umbraco. - -## [Types of Packages](types-of-packages.md) - -Packages for Umbraco 10 and above are installed as NuGet packages. - -## [Creating a Package](creating-a-package.md) - -This short tutorial will teach you how to create a package in the Umbraco backoffice. It will also give a quick overview of what a generated package will contain. - -## [Language file for packages](language-files-for-packages.md) - -Package authors who would like their UI to be multi-lingual can include their own set of language files as part of their package distribution. - -## [Listing a Package on the Umbraco Marketplace](listing-on-marketplace.md) - -Once you've created a package make it available on the Umbraco Marketplace to share it with the community. - -## [Packages on Umbraco Cloud](packages-on-umbraco-cloud.md) - -Things you should know if you are developing for Umbraco Cloud. - -## [Maintaining Packages](maintaining-packages.md) - -Some guidance on how to maintain your package after release. - -## [An Example Package Repository](example-package-repository.md) - -There are many ways to build and deploy your package to NuGet. You will likely have your own approach for organizing a solution and preferred tools for build and deployment. - -If you are looking for inspiration to follow form some tried and tested packages, read more here. diff --git a/10/umbraco-cms/extending/packages/accessibility.md b/10/umbraco-cms/extending/packages/accessibility.md deleted file mode 100644 index 733e096667f..00000000000 --- a/10/umbraco-cms/extending/packages/accessibility.md +++ /dev/null @@ -1,22 +0,0 @@ -# Create accessible Umbraco packages - -Creating accessible packages extends on accessibility in an [Umbraco context](https://www.skrift.io/issues/accessibility-in-an-umbraco-context/). - -The Umbraco UI components have been built to be accessible and have accessibility tests built within them. Building the user interface (UI) using these [Umbraco UI components](https://uui.umbraco.com/) ensures that the package is as accessible as the Umbraco backoffice. - -In addition, any fixes and updates to the UI components will be pushed through to the packages when you rebuild them with the updates. - -## Testing - -Accessibility testing is more a specialist skillset than it is automated testing. The purpose of this document is to outline what can be done to help build accessible packages. It is not a complete list of accessibility tests that can be performed. - -- Build the components using the [Umbraco UI components](https://uui.umbraco.com/) as these have accessibility tests built within them. -- Use the keyboard to tab through the elements on the page checking: - - Does the element tabbed to have a **focus state**? - - Does the **tab order** make sense? - - More on focus, tab orders, other common interactions and techniques for keyboard testing can be found at [WebAIM: Keyboard Accessibility](https://webaim.org/techniques/keyboard/) -- Check the UI with a screen reader. - - [Non Visual Desktop Access (NVDA) is a free Windows screen reader](https://www.nvaccess.org/download/) and some guidelines on screen reader testing are available from [WebAIM: Web Accessibility In Mind](https://webaim.org/articles/screenreader_testing/) -- Install an accessibility testing tool as a plugin into your browser to run automated tests: - - Tools like [axe DevTools](https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd) are built to reduce the number of false positives in a test. -- If the UI does not follow the Umbraco Style, then check the contrast with a tool like the [Web Content Accessibility Guidelines (WCAG) Contrast Checker](https://chrome.google.com/webstore/detail/wcag-color-contrast-check/plnahcmalebffmaghcpcmpaciebdhgdf). This will help ensure contrast. diff --git a/10/umbraco-cms/extending/packages/creating-a-package.md b/10/umbraco-cms/extending/packages/creating-a-package.md deleted file mode 100644 index fc10e04aeeb..00000000000 --- a/10/umbraco-cms/extending/packages/creating-a-package.md +++ /dev/null @@ -1,324 +0,0 @@ ---- -meta.Title: Creating a package -description: Tutorial to create a package in Umbraco ---- - -# Creating a Package - -The goal of this tutorial is to extend Umbraco and create a package. The tutorial's starting point is to create a package out of the dashboard from the [Creating a Custom Dashboard tutorial](../../../Tutorials/Creating-a-Custom-Dashboard/index.md). The process is the same for most packages so feel free to follow along with something else. - -## Creating a package schema in the backoffice - -To create a package, you first need to create a package schema through the Umbraco backoffice: - -1. Go to the `Packages` section. -2. Select `Created` in the top-right corner of the screen. -3. Select the `Create package` button. - - ![Buttons to select for creating a package schema in the backoffice](images/creating-package-menu-v9.png) -4. On the `Create package` page, there are fields that you can use to construct the contents of your package that are based on items from the backoffice. -5. Enter the package name at the top - we will call our dashboard the same as in the mentioned [Tutorial](../../tutorials/creating-a-custom-dashboard.md): `Custom Welcome Dashboard`. - -We will now take a look at the different information that can be filled in: - -### Package Content section - -These values are used to determine which backoffice items the package should contain. We will fill in the following things: - -| Property | Value | Note | -| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Content | _Empty_ | Here, you can include content - e.g. if you want to create a starter kit. Not relevant for this package though. | -| Media | _Empty_ | Here, you can include media - e.g. if you want to add media to the starter kit. Not relevant for this package though. | -| Document Types | _Empty_ | Similar to the Content picker above. It is important to note that if you include content, you will need to also pick all its dependencies in this and the next steps for them to be packaged together! | -| Media Types | _Empty_ | Similar to the Media picker above. It is important to note that if you include media, you will need to also pick all its dependencies in this and the next steps for them to be packaged together! | -| Macros | _Empty_ | See `Document Types` above | -| Languages | _Empty_ | See `Document Types` above - all text is hardcoded or within our own lang folder in this package, so this is not needed. | -| Dictionary | _Empty_ | See `Document Types` above | -| Data Types | _Empty_ | See `Document Types` above | -| Templates | _Empty_ | See `Document Types` above | -| Stylesheets | _Empty_ | These will come from the **wwwroot/css** folder. If you have stylesheets you want to include from other locations (_like App\_Plugins folder_) you can do so at a later step. | -| Scripts | _Empty_ | These will come from the **wwwroot/scripts** folder. If you have scripts you want to include from other locations (_like App\_Plugins folder_) you can do so at a later step. | -| Partial Views | _Empty_ | See `Document Types` above | - -After filling out all the information, we can select **Create** to create the package schema. We will download it and take a closer look at what it contains. - -## Inspecting a package ZIP - -If your package doesn't include backoffice specific items, the result from downloading it will be just a `package.xml` file. Otherwise, if you select media files you will download a ZIP package that looks like this: - -![Content of a ZIP package](images/zip-package-v9.png) - -Additionally to the `package.xml`, there is a folder containing the media items for your package. The rest of the information is recorded in the XML schema document. - -The files that we created from the [Creating a Custom Dashboard Tutorial](../../tutorials/creating-a-custom-dashboard.md) will be discussed at a later point. Now, let's take a look at the `package.xml` file: - -```xml - - - - - Custom Welcome Dashboard - - - - - - - - - - - - - - - -``` - -You will notice that the values for each of the fields we provided can be found inside this XML file. But since our example doesn't require any backoffice items, just the package name is contained. In a different case, the other values will be kept under the respective XML tags. - -## Creating a NuGet package - -This is the next step of preparing your package before install. Umbraco 9 only supports packages using NuGet installation, which enforces better practices for both source control and deployment. Here, you will find how to create a NuGet Package for the custom dashboard that will extend Umbraco's functionality. - -NuGet is the standard package manager for .NET projects. More information about NuGet and how it works can be found on the [Microsoft documentation pages for NuGet](https://docs.microsoft.com/en-us/nuget/what-is-nuget). - -### Generate an empty package using a template - -Assuming you have already installed the Umbraco templates, you can execute the following command in the .NET CLI to create a package project, that will include the necessary configuration for packing and installing your client-side assets: - -``` -dotnet new umbracopackage --name CustomWelcomeDashboard -``` - -{% hint style="info" %} -For a guide on how to install the project templates, follow the 2 steps listed in the [Install the template section](../../fundamentals/setup/install/install-umbraco-with-templates.md). -{% endhint %} - -The outcome is the files generated below: - -![Content of an empty package](images/empty-package-from-template.png) - -Apart from the project file, you can find an empty `package.manifest` inside the **App\_Plugins** folder, which we will replace with the one created from the [Creating a Custom Dashboard Tutorial](../../../Tutorials/Creating-a-Custom-Dashboard/index.md). But more importantly, it also contains a `build/CustomWelcomeDashboard.targets` file. - -This file contains an `msbuild` target that is executed when a project has a dependency on this package. It copies the `App_Plugins` folder into the project on build. This is required for having Umbraco packages in a NuGet package format. - -{% hint style="info" %} -If you are planning to overwrite the contents of the **App\_Plugins** folder, make sure that the subfolder containing your package contents has the same name as the one you specified after the `--name` flag and that the `package.manifest` has the correct path references to your files. -{% endhint %} - -You can also add your custom C# files in the root of the package folder which will be part of the DLL of the package, but for our example, this won't be necessary. - -### Transfer files - -As mentioned previously, let's navigate to the **App\_Plugins** folder and replace its contents with the custom files we created for our new dashboard. - -![App\_Plugins with dashboard files](images/app-pligins-contents.png) - -### Specify package properties - -In this section, we will demonstrate how you can add metadata about the package and its creator(s). - -Now that Umbraco 9 is built on ASP.NET Core, you can add values directly to the package `csproj` file and it will pick them up. If you don't want to manually edit the `csproj` file, you can right-click your project, go to _Properties_ and then to _Package_. There you can insert your specific information: - -![Package properties](images/package-properties.png) - -Here is an example of some basic properties that you can specify in your project file: - -```xml - - - . . . - CustomWelcomeDashboard - ... - umbraco plugin package - 1.0.0 - Umbraco HQ - https://umbraco.com - MIT - - . . . - -``` - -The `Title`, `Description`, `PackageTags` came with the template and we added some further information like `Version`, `Authors`, `PackageProjectUrl` and `PackageLicenseExpression` that we elaborate on below: - -| Property | Value | Note | -| ------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Version | 1.0.0 | This is automatically set to 1.0.0 but can be changed as appropriate. | -| Authors | Your name | Here you get to take credit for your awesome work! | -| PackageProjectUrl | https://umbraco.com | This URL will be shown as the package's URL when others install it. It will likely be a GitHub repository, or similar. | -| PackageLicenseExpression | MIT | The license is set to MIT. Please consider how you want your package licensed. If in doubt when deciding an open-source license there are [good resources available](https://choosealicense.com/licenses/). | - -### Pack it - -It is time to create the actual NuGet package (that is, a _.nupkg_ file). Executing the `dotnet pack` command in the package directory will take care of building the project and outputing the generated NuGet package in the `bin` folder (_the output on the CLI shows the full path to the `.nupkg` file_). - -{% hint style="info" %} -If you want to specify the output location, just execute the following command instead: - -``` -dotnet pack --output MyNugetPackages -``` - -It will pack the project in the current directory and place the resulting package into the `MyNugetPackages` folder. -{% endhint %} - -### Publish it - -To allow other people to use your package you will need to publish it to a public NuGet repository. The most common repository is at [https://nuget.org](https://nuget.org). - -There is comprehensive documentation on how to [Publish a NuGet package to NuGet.org](https://docs.microsoft.com/en-us/nuget/nuget-org/publish-a-package) in the official NuGet documentation, as well as how to [Publish to a private feed](https://docs.microsoft.com/en-us/nuget/hosting-packages/overview) while developing. - -To publish your package to the Umbraco community, use the "[Listing Your Package](https://docs.umbraco.com/umbraco-dxp/marketplace/listing-your-package)" article to feature your package on the Umbraco Marketplace. - -## Installing a NuGet package - -You can install your newly created NuGet package using Visual Studio, Rider, Command Line or editing the project file directly. - -We will continue using the CLI and first create a Umbraco project, and then add the package reference to it: - -``` -dotnet new umbraco -n CustomWelcomeDashboardProject -cd CustomWelcomeDashboardProject -dotnet add package CustomWelcomeDashboard.1.0.0 -dotnet run -``` - -You can check that the NuGet package was referenced in your solution and that the **App\_Plugins** assets were restored successfully. Our simple package is now installed and you can see the custom dashboard in the backoffice. No further actions are required for our example. However, we will go ahead and mention a few more steps necessary for the more complex packages. - -A **different approach** when you want to test it locally without publishing it anywhere is to create a test site of the package. You can use our `dotnet new umbraco` template, this time with a special flag `-p` which will add a project dependency to our package and import the target file from that project. So when you build the new project, it will also copy the **App\_Plugins** folder from the package project into the test project. In the same way, as if it was a NuGet reference. - -This is the full command: - -``` -dotnet new umbraco -n CustomWelcomeDashboardProject -p CustomWelcomeDashboard -``` - -Afterwards, you can enter the `CustomWelcomeDashboardProject` directory, build your Umbraco website using the `dotnet build` command and then run the application. - -### Package migration - -We can run a migration plan for each package that contains Umbraco content (_referenced in the package schema_). - -#### Automatic Package Migration - -If you just want to ship a package that only installs the schema and the content you chose, then you can inherit from the `AutomaticPackageMigrationPlan` as seen below, and specify the package name that will be displayed under the packages _Installed_ tab in the backoffice. You will also need to embed the schema file in the same namespace. - -``` -using Umbraco.Cms.Infrastructure.Packaging; - -namespace CustomWelcomeDashboardProject.Migrations -{ - public class PackageMigrationPlan : AutomaticPackageMigrationPlan - { - public PackageMigrationPlan() : base("Custom Welcome Dashboard") - { - } - } -} -``` - -![Automatic package migration](images/embeded-resource.png) - -{% hint style="info" %} -Whenever the embedded package.xml file changes, the automatic package migration plan is executed again. This is due to the fact that the migration state is based on the file hash. Existing schema or content will not be overwritten in this process. -{% endhint %} - -#### Custom Package Migration - -Instead of creating an automatic package migration plan, we will inherit from the `PackageMigrationPlan` and again specify the name of the package in the base constructor. Further on, we will define the plan using a unique GUID - in the example below we have a single migration called `MyCustomMigration`. - -``` -using System; -using Umbraco.Cms.Core.Packaging; - -namespace CustomWelcomeDashboardProject.Migrations -{ - public class CustomPackageMigrationPlan : PackageMigrationPlan - { - public CustomPackageMigrationPlan() : base("Custom Welcome Dashboard") - { - } - - protected override void DefinePlan() - { - To(new Guid("4FD681BE-E27E-4688-922B-29EDCDCB8A49")); - } - } -} -``` - -The custom migrations can inherit from `PackageMigrationBase` where we can use helper methods to pick up the schema. But we can also use the regular `MigrationBase` class. - -``` -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Infrastructure.Migrations; -using Umbraco.Cms.Infrastructure.Packaging; - -namespace CustomWelcomeDashboardProject.Migrations -{ - public class CustomPackageMigration : PackageMigrationBase - { - public CustomPackageMigration( - IPackagingService packagingService, - IMediaService mediaService, - MediaFileManager mediaFileManager, - MediaUrlGeneratorCollection mediaUrlGenerators, - IShortStringHelper shortStringHelper, - IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, - IMigrationContext context) : base(packagingService, - mediaService, - mediaFileManager, - mediaUrlGenerators, - shortStringHelper, - contentTypeBaseServiceProvider, - context) - { - } - - protected override void Migrate() - { - ImportPackage.FromEmbeddedResource(GetType()).Do(); - - // Additional steps ... - } - } -} -``` - -Here we also added the ZIP file as an embedded resource to the package project. - -![ZIP as an embedded resource](images/embeded-resource-props.png) - -![Automatic package migration](images/embeded-zip-resource.png) - -Whichever migration plan you choose to create, you will be able to see that your package has been installed after the migration is completed. - -![Installed package](images/installed-package.png) - -When using a custom package migration plan, the current state is ignored by default. This causes it to execute all migrations again whenever this isn't the same as the final state of the plan (e.g. if you added a new migration). This is due to the `IgnoreCurrentState` being set to `true` in the `PackageMigrationPlan` base class. You can override this property and set it to `false` again to make it behave like regular migration plans and only run the migrations that have not yet been executed on the current environment. - -### Attended/Unattended migration execution - -After creating a migration plan, the content and schema will automatically be imported either during unattended package migration or from the Packages section in the backoffice. - -By default, all these package migrations are executed unattended during startup but the solution owners can disable this in the configuration. IntelliSense can help, as well as provide further information about the `PackageMigrationsUnattended` setting. Then in the Packages section, there will be an option to run the package migration for each package individually when the `PackageMigrationsUnattended` is set to `false`. - -```json - "Umbraco": { - "CMS": { - . . . - "Unattended": { - "PackageMigrationsUnattended": false - } - } - } -``` - -![Attended package install](images/package-install-attended.png) - -The configuration of package migrations can be different for each environment and makes it possible to have the migration executed unattended on the development environment, but leave them out or manually execute them on other environments. This is useful when you use a tool like Umbraco Deploy or USync as these will migrate the content. diff --git a/10/umbraco-cms/extending/packages/example-package-repository.md b/10/umbraco-cms/extending/packages/example-package-repository.md deleted file mode 100644 index 398053fce05..00000000000 --- a/10/umbraco-cms/extending/packages/example-package-repository.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -meta.Title: An Example Package Repository -description: >- - Suggestions for organizing and Umbraco package source code repository. ---- - -# An Example Package Repository - -There are many ways to build and deploy your package to NuGet. You will likely have your own approach for organizing a solution and preferred tools for build and deployment. - -It may be useful though to review some practices we share here, of how we build packages at Umbraco. - -Some add-ons to the CMS created by Umbraco are closed-source, but we have some we make freely available with open-source repositories. An example is [Umbraco.AuthorizedServices](../../../../marketplace-and-integrations/packages/authorized-services.md), that has a source code repository [here on GitHub](https://github.com/umbraco/Umbraco.AuthorizedServices). - -## Solution Organization - -The solution consists of three projects. - -### Package Project - -The [main package project](https://github.com/umbraco/Umbraco.AuthorizedServices/tree/main/src/Umbraco.AuthorizedServices) lives in `src/`. It contains in the project file a dependency on Umbraco CMS: - -```xml - -``` - -Here we provide an upper bound on the package. This ensures that developers can only install it into projects that are using versions of Umbraco that we have tested the package with. - -When the next major version of Umbraco is released, we'll test and either extend the range or release a new version, as appropriate. - -### Tests Project - -We have a [project for unit tests](https://github.com/umbraco/Umbraco.AuthorizedServices/tree/main/tests/Umbraco.AuthorizedServices.Tests) in `tests/.Tests`. It contains references to `Umbraco.Cms.Tets` and a project reference to the package: - -```xml - -``` - -### Example Website - -Finally there's an [example Umbraco website](https://github.com/umbraco/Umbraco.AuthorizedServices/tree/main/examples/Umbraco.AuthorizedServices.TestSite) that we use for manual testing of the package. It also has a project reference to the package project, allowing us to test updates as they are compiled. - -### Solution Items - -As well as the projects, the following files are added to the solution: - -- [.artifactignore](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.artifactignore) - used by Azure DevOps services to [control which files are uploaded when you publish](https://learn.microsoft.com/en-us/azure/devops/artifacts/reference/artifactignore?view=azure-devops). This helps to reduce pipeline execution time. -- [.editorconfig](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.editorconfig) - used to [enforce consistent coding styles](https://editorconfig.org/) for multiple developers working on the same project across editors and IDEs. -- [.gitignore](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.gitignore) - controls which files are added to source control. -- [.globalconfig](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.globalconfig) - provides [further styling rules for the project files, even if stored outside of the project directory](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-files#global-analyzerconfig). -- [Directory.Build.props](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/Directory.Build.props) - used to provide common setting across all projects in the solution. -- global.json - ensures that the solution is always [built with a consistent version of .NET](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json). We add this when we have a solution that targets a single Umbraco major version. -- [LICENSE.md](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/LICENSE.md) - indicates the license through which the code is available. -- [README.md](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/README.md) - a top-level documentation page for the source code repository. -- [icon.png](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/icon.png) - an icon used for the package on NuGet and the Umbraco Marketplace. -- [umbraco-marketplace.json](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/umbraco-marketplace.json) - provides [additional details about the package when listed on the Umbraco Marketplace](https://docs.umbraco.com/umbraco-dxp/marketplace/listing-your-package). -- [version.json](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/version.json) - provides package versioning information for use by [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning). We use this tool for generating version numbers. - -## Build and Deployment - -We use Azure DevOps pipelines for continuous integration and releasing new versions of the package. The definition of how the project is built is defined in a `.yaml` file that's part of the source code repository. - -The file can be found [here](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/azure-pipeline%20-%20Umbraco.AuthorizedServices.yml). - -Even if using another tool it may be worth reviewing how we have setup our pipeline. It may be you can setup something similar with your own provider. - -### Building the Package - -The build consists of two stages: building the solution and running unit tests. Only if both succeed is the build as a whole considered successful. - -![Azure DevOps build pipeline](./images/azuredevops-build.png) - -### Releasing the Package - -We release the package manually in Azure DevOps, with a two stage process. Firstly we release to a "pre-releases" feed, and then after manual approval, to NuGet. - -![Azure DevOps release pipeline](./images/azuredevops-release.png) - - - - - - diff --git a/10/umbraco-cms/extending/packages/good-practice-and-defaults.md b/10/umbraco-cms/extending/packages/good-practice-and-defaults.md deleted file mode 100644 index 102fb9d91ec..00000000000 --- a/10/umbraco-cms/extending/packages/good-practice-and-defaults.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -description: Information on good practices and common defaults for Umbraco package development. ---- - -# Good practice and defaults - -This document provides guides and notes on package development. It includes good practice guidelines that will help you maintain and support your package through multiple releases and versions of Umbraco. These good practices are not prescriptive, but offer a guide as to what often works well, and not-so-well, when developing packages for Umbraco. - -## Backoffice assets (JS/CSS/HTML) - -To extend the Umbraco backoffice, a package can provide files such as a `package.manifest` and AngularJS views/controllers that should be stored within the `App_Plugins` folder. It's recommended to put all files in a subfolder with a unique name, preferably using the package name, like `App_Plugins\MyPackage`. - -Files in the `App_Plugins` folder will be publicly available on the website even though they are not in the `wwwroot` folder. You should not store sensitive information in the `App_Plugins` folder. - -Files in the `App_Plugins` folder should be considered immutable. This means that they are not something a user of your package is expected to change on their site. - -The default delivery method for files to the `App_Plugins` folder is via a `.targets` file within a package. This means when a website is built, the files in this folder are copied over from the NuGet cache. When this happens, any changes a user might have made to these files will be lost. Equally, if the user performs a `dotnet clean` on a solution, all files in the `App_Plugins` folder will be deleted. - -{% hint style="info" %} -If you have files that you expect users of your package to alter you should not place them in the `App_Plugins` folder. -{% endhint %} - -## Views - -Views are used to render content on the front end of a website. If your package provides a way for the user to present the content publicly, you should copy these files to the views folder. - -As the files will still be copied during build you should ensure your target file does not overwrite newer or altered files. You should also ensure that it doesn't delete files on clean. - -{% hint style="info" %} -When you have a package that contains many views you might consider building a dotnet template or Razor Class Library (RCL) instead. By doing this, the files will not pollute your user's solutions. -{% endhint %} - -## License files - -Umbraco products store their licenses in `/umbraco/Licenses`. It is recommended for third-party packages that require license files to also store their license files in this location. - -The default `.gitignore` for Umbraco templates will include any files in the `/Licenses` folder while ignoring most of the rest of the Umbraco folder. - -{% hint style="info" %} -The `/umbraco/Licenses` folder does not exist on a fresh installation of Umbraco. You need to create it manually before you save your license file to this folder. -{% endhint %} - -## Operating system considerations - -Umbraco (version 9 and up) is an ASP.NET Core application and can be run on multiple operating systems (Windows, Linux and macOS). When developing packages there are a few things you should be aware of for your package to run on all possible operating systems. - -### Case sensitivity - -The Linux and macOS file systems are case-sensitive by default. This means that `App_Plugins/myPackage` is a different location from `app_plugins/MyPACKAGE`. When building your package you should ensure that you always refer to folders and paths in a consistent way. - -A good way to ensure consistency is to use constants in your code to define file or folder locations. - -{% hint style="info" %} -You can adjust the case sensitivity of a Windows folder by running a command against a newly created/empty folder: - -```bash -fsutil.exe file queryCaseSensitiveInfo -``` - -{% endhint %} - -#### Case sensitivity in default files and folders - -Some folders within Umbraco will already exist for all installations. If you access these folders, you need to be aware of the case used to ensure you end up in the correct place: - -| Folder | Note | -|-|-| -| /App_Plugins | Uppercase `A` and `P` | -| /App_Plugins/[Ll]ang | Uppercase `L` (in Umbraco 9.3 and higher can be either uppercase `L` or lowercase `l` | -| /Views | Uppercase `V` | -| /umbraco/Licenses | Lowercase `u` and uppercase `L` | -| /config | Lowercase `c` | - -{% hint style="info" %} -If you create a custom section/tree, Umbraco will build paths based on the name of that section or tree. These folder paths will be case-sensitive. - -For example: if you have a custom tree with the `treeAlias` of `MyCustomTree` Umbraco will look for files in `App_Plugins\MyPackage\backoffice\MyCustomTree\`. -{% endhint %} - -### File/folder locations - -You should never hardwire a file or folder location into code. Instead, it is recommended to follow either of the options below: - -* Access files using the ASP.NET Core file providers from `IHostingEnvironment`. -* Use the built-in methods to access well-known locations (see below). - -#### Temp folder - -The location of the Umbraco temp folder can be controlled via configuration and cannot be assumed. Use the `IHostingEnvironment.LocalTempPath` variable to locate the temp folder. - -```csharp -var localTempRoot = Path.GetFullPath(hostingEnvironment.LocalTempPath); -``` - -#### Relative paths - -If you require the path of a folder relative to the site root, you can use the `IHostingEnvironment` method to map a path: - -```csharp -// Full physical path to the content/project root -var contentRootPath = hostingEnvironment.MapPathContentRoot("~/"); -// Full physical path to the web root (served publicly) -var webRootPath = hostEnvironment.MapPathWebRoot("~/"); -// Absolute path to use as URL -var absolutePath = hostEnvironment.ToAbsolute("~/"); -``` - -### Folder/file system access - -It is not recommended to assume things about the folder structure of a site or use direct I/O commands to access the file system. Access to the disk within an ASP.NET Core site is usually managed with File Providers. You can access the file providers from the `IWebHostEnvironment` class. - -Example: If you want to read `robots.txt` from the `wwwroot` folder, use `WebRootFileProvider` in a controller to get to the root of the site and read the file: - -```csharp -public class MyController: UmbracoAuthorizedJsonController -{ - public MyController(IWebHostEnvironment webHostEnvironment) - { - var webRootProvider = webHostEnvironment.WebRootFileProvider; - - var myFileInfo = webRootProvider.GetFileInfo("robots.txt"); - if (myFileInfo.Exists) - { - using (var stream = myFileInfo.CreateReadStream()) - { - using(var streamReader = new StreamReader(stream)) - { - var text = streamReader.ReadToEnd(); - } - } - } - } -} -``` - -{% hint style="info" %} -This is the preferred method for file I/O. Not all files served up by a site are placed in the `wwwroot` folder when you expect them to be. This is especially true if the site is using Razor Class Library projects to insert static files. -{% endhint %} - -### Path manipulation - -Building folder path strings manually can cause problems when swapping between file systems. Windows uses the backslash character ('\\') to separate folders and files while Linux uses the forward slash ('/'). - -#### Example - -On Windows, a file might be located at `d:\website\robots.txt` while on Linux this might look like `/home/website/robots.txt` instead. - -You should use the .NET `Path` methods wherever possible when building paths to ensure that the correct path is built: - -```csharp -// WRONG: Don't build paths manually -var myPath = webrootPath + "\robots.txt"; - -// CORRECT: Build the path using the correct separator for the current file system -var myPath = Path.Combine(webrootPath, "robots.txt"); -``` - -If you need to build a path manually, use `Path.DirectorySeparatorChar` instead to get the correct separator for the file system. - -## Settings - -Most packages will require some settings to be stored for the users to control in order to change the behavior of the package. Where you store these settings will depend a lot on the nature of the package. - -### Property Editors - -Property Editors should store their settings as part of their Data Type in Umbraco. This is the standard way property editor behavior is controlled while it is familiar to users and supported by deployment tools. - -### Do not save to appsettings.json - -You should not alter `appsettings.json` via code. - -Settings in ASP.NET Core are merged from a number of different locations at runtime. You cannot guarantee that `appsettings.json` is the location that a setting is read from and your users may not want certain settings in that file. You can read settings from the configuration, but you cannot assume they have come from `appsettings.json`. - -### Settings locations - -There are many options for where you might save your settings and a lot will depend on the nature of your package. - -Below you can find pros and cons for different places where you might save the settings for your package. - -#### Save to the database - -Settings can be saved to the database. Settings can be stored in the database using the Umbraco `IKeyValueService`, and for more complex settings you can use a custom database table. - -- Pros: - - Settings will be accessible directly from the database, and not dependent on deployed files on disk. -- Cons: - - Setup is required to create the database tables for the settings to live in. - - The settings will only be available to the specific instance of the site, and any settings will not be deployed between a local, development, or staging site. - -#### Save to disk - -You can choose to save the settings to disk. As an example, the settings can be saved in the `/config` folder at the root of the site. - -- Pros: - - Settings will be accessible to the site and can be included in deployments between sites. -- Cons: - - You cannot guarantee that the folder or files will be present on a site or that they will be writable. - - Using your own config means your users cannot harness the power of the .NET Core configuration system and move settings to environment variables or other key/value stores. This means that sensitive information may end up on disk. - -#### Provide the users with appsettings.json snippets - -You could choose to provide your users with a snippet they can copy into their `appsettings.json` file. This will ensure that the settings are stored in the correct location. - -- Pro: Allows your users to fully control how and where the settings are stored (eg. secure key/value stores). -- Con: Requires the user to edit files on disk to get the settings in place. diff --git a/10/umbraco-cms/extending/packages/images/PackagesPage.png b/10/umbraco-cms/extending/packages/images/PackagesPage.png deleted file mode 100644 index cff25527501..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/PackagesPage.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/app-pligins-contents (1).png b/10/umbraco-cms/extending/packages/images/app-pligins-contents (1).png deleted file mode 100644 index c0350372ad7..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/app-pligins-contents (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/app-pligins-contents.png b/10/umbraco-cms/extending/packages/images/app-pligins-contents.png deleted file mode 100644 index c0350372ad7..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/app-pligins-contents.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/app-plugins-starterkit (1).png b/10/umbraco-cms/extending/packages/images/app-plugins-starterkit (1).png deleted file mode 100644 index f69d24e28df..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/app-plugins-starterkit (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/app-plugins-starterkit.png b/10/umbraco-cms/extending/packages/images/app-plugins-starterkit.png deleted file mode 100644 index f69d24e28df..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/app-plugins-starterkit.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/azuredevops-build.png b/10/umbraco-cms/extending/packages/images/azuredevops-build.png deleted file mode 100644 index 763fbe991d3..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/azuredevops-build.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/azuredevops-release.png b/10/umbraco-cms/extending/packages/images/azuredevops-release.png deleted file mode 100644 index 426d86e170c..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/azuredevops-release.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-installed-packages (1).png b/10/umbraco-cms/extending/packages/images/backoffice-installed-packages (1).png deleted file mode 100644 index 74651ae2ada..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-installed-packages (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-installed-packages.png b/10/umbraco-cms/extending/packages/images/backoffice-installed-packages.png deleted file mode 100644 index 74651ae2ada..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-installed-packages.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-package-section (1).png b/10/umbraco-cms/extending/packages/images/backoffice-package-section (1).png deleted file mode 100644 index dca87d21e51..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-package-section (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-package-section.png b/10/umbraco-cms/extending/packages/images/backoffice-package-section.png deleted file mode 100644 index dca87d21e51..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-package-section.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-packages-section (1).png b/10/umbraco-cms/extending/packages/images/backoffice-packages-section (1).png deleted file mode 100644 index f14549ef229..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-packages-section (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-packages-section-package (1).png b/10/umbraco-cms/extending/packages/images/backoffice-packages-section-package (1).png deleted file mode 100644 index c31ad803478..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-packages-section-package (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-packages-section-package.png b/10/umbraco-cms/extending/packages/images/backoffice-packages-section-package.png deleted file mode 100644 index c31ad803478..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-packages-section-package.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/backoffice-packages-section.png b/10/umbraco-cms/extending/packages/images/backoffice-packages-section.png deleted file mode 100644 index f14549ef229..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/backoffice-packages-section.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/cloud-flow.png b/10/umbraco-cms/extending/packages/images/cloud-flow.png deleted file mode 100644 index 1880ca8d129..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/cloud-flow.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/creating-package-menu-v9 (1).png b/10/umbraco-cms/extending/packages/images/creating-package-menu-v9 (1).png deleted file mode 100644 index da73453c0a6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/creating-package-menu-v9 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/creating-package-menu-v9.png b/10/umbraco-cms/extending/packages/images/creating-package-menu-v9.png deleted file mode 100644 index da73453c0a6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/creating-package-menu-v9.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/creating-package-menu.png b/10/umbraco-cms/extending/packages/images/creating-package-menu.png deleted file mode 100644 index 2bbadf1c1ba..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/creating-package-menu.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/display-retired.png b/10/umbraco-cms/extending/packages/images/display-retired.png deleted file mode 100644 index 9584bcae232..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/display-retired.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/download-package-button.png b/10/umbraco-cms/extending/packages/images/download-package-button.png deleted file mode 100644 index ed8d1705221..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/download-package-button.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/embeded-resource (1).png b/10/umbraco-cms/extending/packages/images/embeded-resource (1).png deleted file mode 100644 index f3ac2e59a1a..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/embeded-resource (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/embeded-resource-props (1).png b/10/umbraco-cms/extending/packages/images/embeded-resource-props (1).png deleted file mode 100644 index ee8e0b6a49e..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/embeded-resource-props (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/embeded-resource-props.png b/10/umbraco-cms/extending/packages/images/embeded-resource-props.png deleted file mode 100644 index ee8e0b6a49e..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/embeded-resource-props.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/embeded-resource.png b/10/umbraco-cms/extending/packages/images/embeded-resource.png deleted file mode 100644 index f3ac2e59a1a..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/embeded-resource.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/embeded-zip-resource (1).png b/10/umbraco-cms/extending/packages/images/embeded-zip-resource (1).png deleted file mode 100644 index 4b85628f1a0..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/embeded-zip-resource (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/embeded-zip-resource.png b/10/umbraco-cms/extending/packages/images/embeded-zip-resource.png deleted file mode 100644 index 4b85628f1a0..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/embeded-zip-resource.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/empty-package-from-template (1).png b/10/umbraco-cms/extending/packages/images/empty-package-from-template (1).png deleted file mode 100644 index 0a692a5c54e..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/empty-package-from-template (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/empty-package-from-template.png b/10/umbraco-cms/extending/packages/images/empty-package-from-template.png deleted file mode 100644 index 0a692a5c54e..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/empty-package-from-template.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/flag-as-retired.png b/10/umbraco-cms/extending/packages/images/flag-as-retired.png deleted file mode 100644 index bf4104ef5d4..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/flag-as-retired.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/forum-create.png b/10/umbraco-cms/extending/packages/images/forum-create.png deleted file mode 100644 index 7df1e4bd4ca..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/forum-create.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/forums-display.png b/10/umbraco-cms/extending/packages/images/forums-display.png deleted file mode 100644 index accb6880390..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/forums-display.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/forums-link.png b/10/umbraco-cms/extending/packages/images/forums-link.png deleted file mode 100644 index 3c7540216a6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/forums-link.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/fromArtifact.png b/10/umbraco-cms/extending/packages/images/fromArtifact.png deleted file mode 100644 index 22d50e7f5f1..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/fromArtifact.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/hitting-breakpoints.png b/10/umbraco-cms/extending/packages/images/hitting-breakpoints.png deleted file mode 100644 index 2fbe4666e6e..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/hitting-breakpoints.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/installed-package (1).png b/10/umbraco-cms/extending/packages/images/installed-package (1).png deleted file mode 100644 index 715cf1f9bcb..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/installed-package (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice (1).png b/10/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice (1).png deleted file mode 100644 index 48ee6810320..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice.png b/10/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice.png deleted file mode 100644 index 48ee6810320..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/installed-package.png b/10/umbraco-cms/extending/packages/images/installed-package.png deleted file mode 100644 index 715cf1f9bcb..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/installed-package.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/nuget-installing-options (1).png b/10/umbraco-cms/extending/packages/images/nuget-installing-options (1).png deleted file mode 100644 index 95d91944f82..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/nuget-installing-options (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/nuget-installing-options.png b/10/umbraco-cms/extending/packages/images/nuget-installing-options.png deleted file mode 100644 index 95d91944f82..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/nuget-installing-options.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/nuget-package-in-manager (1).png b/10/umbraco-cms/extending/packages/images/nuget-package-in-manager (1).png deleted file mode 100644 index d5e1b3b80a5..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/nuget-package-in-manager (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/nuget-package-in-manager.png b/10/umbraco-cms/extending/packages/images/nuget-package-in-manager.png deleted file mode 100644 index d5e1b3b80a5..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/nuget-package-in-manager.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/package-files-list.png b/10/umbraco-cms/extending/packages/images/package-files-list.png deleted file mode 100644 index b3d5b4843ed..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/package-files-list.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/package-install-attended.png b/10/umbraco-cms/extending/packages/images/package-install-attended.png deleted file mode 100644 index c6f31569b02..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/package-install-attended.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/package-options.gif b/10/umbraco-cms/extending/packages/images/package-options.gif deleted file mode 100644 index 0bd1a81695f..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/package-options.gif and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/package-properties (1).png b/10/umbraco-cms/extending/packages/images/package-properties (1).png deleted file mode 100644 index b7fb1b0d7f5..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/package-properties (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/package-properties.png b/10/umbraco-cms/extending/packages/images/package-properties.png deleted file mode 100644 index b7fb1b0d7f5..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/package-properties.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/property-editor.png b/10/umbraco-cms/extending/packages/images/property-editor.png deleted file mode 100644 index 7b049f578ca..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/property-editor.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-content (1).png b/10/umbraco-cms/extending/packages/images/removing-content (1).png deleted file mode 100644 index 3fa0db3b6ad..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-content (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-content.png b/10/umbraco-cms/extending/packages/images/removing-content.png deleted file mode 100644 index 3fa0db3b6ad..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-content.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-datatypes (1).png b/10/umbraco-cms/extending/packages/images/removing-datatypes (1).png deleted file mode 100644 index 7cd36ad62eb..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-datatypes (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-datatypes.png b/10/umbraco-cms/extending/packages/images/removing-datatypes.png deleted file mode 100644 index 7cd36ad62eb..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-datatypes.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-document-types (1).png b/10/umbraco-cms/extending/packages/images/removing-document-types (1).png deleted file mode 100644 index 40d0ad2a49d..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-document-types (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-document-types.png b/10/umbraco-cms/extending/packages/images/removing-document-types.png deleted file mode 100644 index 40d0ad2a49d..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-document-types.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-media (1).png b/10/umbraco-cms/extending/packages/images/removing-media (1).png deleted file mode 100644 index 160ccfac9f6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-media (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-media.png b/10/umbraco-cms/extending/packages/images/removing-media.png deleted file mode 100644 index 160ccfac9f6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-media.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-partials (1).png b/10/umbraco-cms/extending/packages/images/removing-partials (1).png deleted file mode 100644 index 1fc93d8ccaa..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-partials (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-partials.png b/10/umbraco-cms/extending/packages/images/removing-partials.png deleted file mode 100644 index 1fc93d8ccaa..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-partials.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-templates (1).png b/10/umbraco-cms/extending/packages/images/removing-templates (1).png deleted file mode 100644 index 08beb8e2c15..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-templates (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/removing-templates.png b/10/umbraco-cms/extending/packages/images/removing-templates.png deleted file mode 100644 index 08beb8e2c15..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/removing-templates.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/select-files-for-package.png b/10/umbraco-cms/extending/packages/images/select-files-for-package.png deleted file mode 100644 index d059e30fe7d..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/select-files-for-package.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/seochecker-after-removal (1).png b/10/umbraco-cms/extending/packages/images/seochecker-after-removal (1).png deleted file mode 100644 index 9eb77e23309..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/seochecker-after-removal (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/seochecker-after-removal.png b/10/umbraco-cms/extending/packages/images/seochecker-after-removal.png deleted file mode 100644 index 9eb77e23309..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/seochecker-after-removal.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/seochecker-app-plugins (1).png b/10/umbraco-cms/extending/packages/images/seochecker-app-plugins (1).png deleted file mode 100644 index b2b2ec0b92c..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/seochecker-app-plugins (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/seochecker-app-plugins.png b/10/umbraco-cms/extending/packages/images/seochecker-app-plugins.png deleted file mode 100644 index b2b2ec0b92c..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/seochecker-app-plugins.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/seochecker-content-section (1).png b/10/umbraco-cms/extending/packages/images/seochecker-content-section (1).png deleted file mode 100644 index 5c83b0d11e6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/seochecker-content-section (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/seochecker-content-section.png b/10/umbraco-cms/extending/packages/images/seochecker-content-section.png deleted file mode 100644 index 5c83b0d11e6..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/seochecker-content-section.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/specify-version-info.png b/10/umbraco-cms/extending/packages/images/specify-version-info.png deleted file mode 100644 index ece295fecdb..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/specify-version-info.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/steppingThroughCode.png b/10/umbraco-cms/extending/packages/images/steppingThroughCode.png deleted file mode 100644 index 2edb08c90e1..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/steppingThroughCode.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/team-link.png b/10/umbraco-cms/extending/packages/images/team-link.png deleted file mode 100644 index 61008aef4e3..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/team-link.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager (1).png b/10/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager (1).png deleted file mode 100644 index b63cc056930..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager.png b/10/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager.png deleted file mode 100644 index b63cc056930..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/valueconnector.gif b/10/umbraco-cms/extending/packages/images/valueconnector.gif deleted file mode 100644 index 40948d682f1..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/valueconnector.gif and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/vs-cleaning-solution (1).png b/10/umbraco-cms/extending/packages/images/vs-cleaning-solution (1).png deleted file mode 100644 index 435e2505b06..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/vs-cleaning-solution (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/vs-cleaning-solution.png b/10/umbraco-cms/extending/packages/images/vs-cleaning-solution.png deleted file mode 100644 index 435e2505b06..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/vs-cleaning-solution.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/zip-package-v9 (1).png b/10/umbraco-cms/extending/packages/images/zip-package-v9 (1).png deleted file mode 100644 index 169bbfb1591..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/zip-package-v9 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/zip-package-v9.png b/10/umbraco-cms/extending/packages/images/zip-package-v9.png deleted file mode 100644 index 169bbfb1591..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/zip-package-v9.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/images/zip-package.png b/10/umbraco-cms/extending/packages/images/zip-package.png deleted file mode 100644 index 0ec18b86ceb..00000000000 Binary files a/10/umbraco-cms/extending/packages/images/zip-package.png and /dev/null differ diff --git a/10/umbraco-cms/extending/packages/installing-and-uninstalling-packages.md b/10/umbraco-cms/extending/packages/installing-and-uninstalling-packages.md deleted file mode 100644 index 1e4f8170ffa..00000000000 --- a/10/umbraco-cms/extending/packages/installing-and-uninstalling-packages.md +++ /dev/null @@ -1,235 +0,0 @@ ---- -description: >- - The process of installing and, in turn, uninstalling packages in your Umbraco - CMS website depends on the version and package type. ---- - -# Installing and Uninstalling Packages - -This article will cover the process of installing as well as uninstalling packages from your Umbraco CMS website. - -As the article will cover both NuGet packages and zip file packages, it is important to know the distinction: - -* **NuGet packages**: Modern Umbraco (Umbraco 10+) and Legacy Umbraco (Umbraco 8 and earlier versions). -* **Package zip files**: Legacy Umbraco (Umbraco 8 and earlier versions) only. - -Learn more about the different types of packages in the [Types of packages](types-of-packages.md) article. - -## Installing packages - -In the Umbraco Backoffice, you will find a **Packages** section that displays the [Umbraco Marketplace](https://marketplace.umbraco.com/). From here you can browse all community-made as well as official Umbraco packages for the Umbraco CMS. - -![Backoffice - Packages section]() - -{% hint style="warning" %} -For Umbraco CMS version 8 and earlier versions, the Packages section displays the [Packages site on Our](https://our.umbraco.com/packages/). -{% endhint %} - -{% tabs %} -{% tab title="NuGet package" %} -Navigating to a specific package in the section will present you with an overview of the package, as well as an install snippet for NuGet CLI. - -![Backoffice - Starter Kit package]() - -The packages can be installed by using: - -* **NuGet Package Manager** in Visual Studio -* **Package Manager Console** in Visual Studio -* .NET CLI (usually accessible from the terminal/command prompt of your system) - -For example, to install the StarterKit package for the Umbraco CMS the command would be: - -`dotnet add package Umbraco.TheStarterKit` - -Navigating to the NuGet Package Manager in Visual Studio is more visual, and gives you an overview of already installed packages. - -![Visual Studio - nuget packages manager]() - -The Package Manager has an integrated search function that allows you to find any public NuGet package and install it on the project. - -![Visual Studio - finding The Starter Kit](images/nuget-package-in-manager.png) - -Once the package has been installed, it will show up under the **Packages** section in the backoffice, under **Installed** tab. - -![Backoffice - installed packages]() -{% endtab %} - -{% tab title="Package zip file" %} -{% hint style="warning" %} -Package zip files are only available for Umbraco 8 or earlier versions. -{% endhint %} - -Once you have downloaded an Umbraco package zip file, you can install it in the Umbraco backoffice by following the steps below: - -* Navigate to the **Packages** section. -* Select **Install local** on the top-right side of the page. -* Drag'n drop the package onto the page or use the file explorer to select the package zip file. -* Accept terms of use to confirm the package installation. - -The package will be installed and any necessary reboots of the site will be initiated. - -You can also install packages directly when browsing the packages in the Umbraco backoffice. This is usually preferred in order to ensure that the package is compatible with the Umbraco CMS version used. - -* Navigate to the specific package you want to install. -* Click **Install package** in the right-hand side of the page. -* Confirm the installation. - -The package will be install and the site will be rebooted. -{% endtab %} -{% endtabs %} - -## Uninstalling packages - -Uninstalling packages is not always as straightforward as installing them. - -In this section, we will provide two examples of uninstalling a package - the StarterKit package and the SEOChecker package. - -### Uninstalling packages like the StarterKit - -{% hint style="info" %} -Keep in mind that this particular guide targets a specific package. There are many packages out there, and each one is different. The exact steps presented here might not work the exact same way for all the packages, though the general approach should still apply. -{% endhint %} - -The Starter Kit provides you with a boilerplate website solution to build upon. The package installs Document Types, Templates, media, content, and everything else needed to set up a small website. There is little custom code/functionality involved which is usually the case for such starter kit or sample-site packages. - -To uninstall a package, either run a command or use the NuGet Package Manager in Visual Studio. - -`dotnet remove package Umbraco.TheStarterKit` - -![Visual Studio - uninstalling via Package Manager]() - -{% hint style="info" %} -If you are using Umbraco 8 or an earlier version you uninstall the packages directly from the **Packages** section of the Umbraco backoffice. - -1. Navigate to the **Installed** tab in the **Packages** section. -2. Click **Uninstall package** next to the package you want to uninstall. -3. Confirm that action by checking **Confirm package uninstall**. -{% endhint %} - -It is recommended to clean the solution after removing any package. This can be done by right-clicking the project in Visual Studio and choosing the _Clean_ option, or using the `dotnet clean` command. - -![Visual Studio - clean solution]() - -#### Removing package leftovers from the backoffice - -With packages like the StarterKit, the process does not end there. While the package is gone, content - and everything else needed for the website - is still available in the backoffice. To fully remove this kind of package, additional steps are needed. - -
- -Remove content provided by the package - -There is no universal way to tell what content comes from a package, and what content is custom-made. In the Content section, delete individual nodes accordingly. If the goal is to fully remove the package and clean the site, all the content can be removed (and the recycle bin emptied). - -Backoffice - removing content - -
- -
- -Remove media provided by the package - -Similar to content, media also might have to be removed. - -Backoffice - removing media - -
- -
- -Remove Document Types - -Document Types can be removed from the **Settings** section. If fully removing the package, all Document Types can be deleted, as there are no default Document Types in a clean-slate Umbraco installation. - -Backoffice - removing document types - -
- -
- -Removing Data Types - -As opposed to Document Types, there are some Data Types that are available out of the box when Umbraco is installed. It is not recommended to remove them. The safe approach is to delete any item that starts with a Document Type prefix and includes multiple dashes. That is the default naming convention for new configurations of Data Types (Example: "Blog - How many posts should be shown - Slider") - -Backoffice - removing data types - -
- -
- -Removing Templates - -No Templates are available out of the box in a new installation. If cleaning up after a package, it would be okay to delete all that are present - -Backoffice - removing templates - -
- -
- -Removing Partial Views - -Out of the box, there are a few views available in the `blocklist` and `grid` folders. Everything else can theoretically be removed. - -Backoffice - removing partial views - -
- -
- -Cleaning leftover files on disk - -Some packages might reference other items. For example, installing the StarterKit also adds `Bergmania.OpenStreetMap` to your project. That component will show up as installed in the backoffice even after uninstalling the NuGet package. - -Backoffice - Packages section - leftover dependency - -In many cases, custom dashboards, editors, and scripts are left in the `App_Plugins` folder after a package has been uninstalled via NuGet. These files also have to be deleted manually. - -Visual Studio - App Plugins leftover files - -
- -### Uninstalling packages like the SEOChecker - -{% hint style="info" %} -Keep in mind that this particular guide targets a specific package. There are many packages out there, and each one is different. The exact steps presented here might not work the exact same way for all the packages, though the general approach should still apply. -{% endhint %} - -More advanced packages that add functionality on top of Umbraco, usually rely on providing custom, compiled code. That being said, many of such packages also implement custom Sections, Dashboards, editors, and views. - -In this example, we will be using the SEOChecker package. This package allows developers of the site to add custom properties to Document Types used to track search engine optimization practices. - -An example use case of the SEOChecker property on a Document Type, as presented in the Content section: - -![SEOChecker in content]() - -To uninstall the SEOChecker from a website, the first step is to remove the package via a `dotnet` command or use the NuGet Package Manager. - -The following command can be used for uninstalling the package: - -`dotnet remove package SEOChecker` - -After that, cleaning the solution is recommended. - -![Visual Studio - clean solution]() - -
- -Cleaning leftover files on disk - -While uninstalling the package would remove most of the custom code, the `App_Plugins` folder has to be cleaned manually. - -SEOChecker files in App Plugins - -Removing _seochecker_ folder from `App_Plugins` will clean up the leftover backoffice section and dashboards. - -
- -## Consequences of removing packages - -If content on the website relies on having a custom Property Editor or a data source installed, those properties will default to a `label` Data Type. All previously saved content in the property will in turn be converted to a string. - -In the case of the SEOChecker, the custom property added from the package would look like this after all the package files have been removed: - -![The SEOChecker in Content after removing the package]() - -Depending on the packages and the implementation, rendering of content from custom editors, or any frontend functionality dependent on external code, might not work correctly. It is always recommended to inspect the frontend of the site after removing any packages. diff --git a/10/umbraco-cms/extending/packages/language-files-for-packages.md b/10/umbraco-cms/extending/packages/language-files-for-packages.md deleted file mode 100644 index bc54dd38bd3..00000000000 --- a/10/umbraco-cms/extending/packages/language-files-for-packages.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -meta.Title: "Language file for packages" -description: "Information on how to use language files to make your Umbraco package UI support multiple languages" ---- - -# Language file for packages - -Umbraco Core includes language files, but package authors must provide their own for multi-lingual UI. - -## Including new language keys - -For each language your package supports, you include an .xml file in the same format as the core language files, named with its language code. The language files must be located in a `Lang` folder inside your package folder in `App_Plugins`. If your package assets are in `/App_Plugins/mypackage` all language files must be placed in the following locations: - -- English keys: `/App_Plugins/mypackage/Lang/en-US.xml` -- Danish keys: `/App_Plugins/mypackage/Lang/da-DK.xml` - -{% hint style="info" %} -The `App_Plugins` version of the `Lang` directory is case sensitive on Linux systems, so make sure that it start with a capital `L`. -{% endhint %} - -## Language file format - -Each language file can include one or more area. Each area contains a collection of language keys with the translation. - -For reference on the language file format see the core [language files on GitHub](https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Core/EmbeddedResources/Lang) - -### Sample structure - -```xml - - - - The Umbraco community - http://mydomain.com - - - Min nøgle - Min anden nøgle - - -``` diff --git a/10/umbraco-cms/extending/packages/listing-on-marketplace.md b/10/umbraco-cms/extending/packages/listing-on-marketplace.md deleted file mode 100644 index 2cc27f0408c..00000000000 --- a/10/umbraco-cms/extending/packages/listing-on-marketplace.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -description: Information on how to list your package on the Umbraco Marketplace. ---- - -# Listing on the Umbraco Marketplace - -The [Umbraco Marketplace](https://marketplace.umbraco.com) is a website built and maintained by Umbraco HQ to support searching and reviewing packages. - -It lists all commercial and open-source packages that the community has made available on NuGet. - -More information, including details of the steps for listing, are available at the dedicated [documentation space for the Marketplace](https://docs.umbraco.com/umbraco-dxp/marketplace/introduction). diff --git a/10/umbraco-cms/extending/packages/maintaining-packages.md b/10/umbraco-cms/extending/packages/maintaining-packages.md deleted file mode 100644 index 342acd5685a..00000000000 --- a/10/umbraco-cms/extending/packages/maintaining-packages.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -meta.Title: Maintaining Umbraco Packages -description: >- - Once you've created and published your package, here is what's involved in - it's ongoing maintenance ---- - -# Maintaining packages - -Once you've created and published your package, what's involved in its ongoing maintenance? - -## Updating with new Umbraco major versions - -Umbraco will regular release update to the CMS as patch or minor versions. These are verified to be backwards compatible. As such there's no expectation that a package may break when a new version of this type comes out. - -When a new major version of Umbraco is released, there will be breaking changes. You should test your package on this latest version to confirm it still works. Unless there's been a significant change to the CMS, many packages will continue to work with the new major version without any update. However you may be using a service or API that has undergone a breaking change. - -If this happens, the changes will be documented and you should be able to update your code, recompile and test. After that you can release a new major version of your own package. - -Even if there are no breaking changes that affect you, it's worth also looking for any code you using that is marked as obsolete. Umbraco will obsolete public methods or constructors that are expected to be removed in a future major version. - -### Referencing Umbraco dependencies - -When creating a package with Umbraco you will be taking a dependency on at least one Umbraco package. You will do this in the `.csproj` file for your package: - -```xml - -``` - -As indicated, this states the package is compatible with Umbraco 10 and any future version. This would allow the developer to install the package into an Umbraco 12 or 13 solution for example. - -If you want to maintain tighter control over this, you can specify an upper bound, like this: - -```xml - -``` - -This states that the package is compatible with Umbraco 10, 11 and 12, but not 13. Thus it prevents anyone installing your package into an Umbraco solution that you haven't verified compatibility with. Once you have, you can increase the bound or otherwise update the dependent Umbraco version as appropriate. - -## Manage feature requests and issues - -If you want to encourage feedback, feature requests, and issue reports then you should make available an issue tracker. - -This can be [provided as information about your package](https://docs.umbraco.com/umbraco-dxp/marketplace/listing-your-package) and will be linked from your package's page on the Umbraco Marketplace. Specifically you should populate the `IssueTrackerUrl` field. - -## Package no longer required? - -After some time it could be that your package should no longer be used. Perhaps it is now too old, or it has been superseded by another one that you recommend instead. - -You can indicate this by [deprecating your package on NuGet](https://learn.microsoft.com/en-us/nuget/nuget-org/deprecate-packages). diff --git a/10/umbraco-cms/extending/packages/packages-on-umbraco-cloud.md b/10/umbraco-cms/extending/packages/packages-on-umbraco-cloud.md deleted file mode 100644 index 791cfd218c1..00000000000 --- a/10/umbraco-cms/extending/packages/packages-on-umbraco-cloud.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -meta.Title: Packages on Umbraco Cloud -v9-equivalent: >- - https://github.com/umbraco/UmbracoCMSDocs/blob/main/Articles/Packages/packages-on-Umbraco-Cloud.md -needsv9Update: 'true' -description: Things to consider for package development and usage in Umbraco Cloud ---- - -# Packages on Umbraco Cloud - -If you want to use or develop packages for Umbraco Cloud there are a few things to consider and be aware of. The two most important things to know about are - -* [How you should store data on Cloud](packages-on-umbraco-cloud.md#storing-data) -* [Using custom property editors with Deploy](packages-on-umbraco-cloud.md#valueconnectors) - -## Storing data - -When developing a package you will sometimes store data, this can be data in many forms - Umbraco schema / content, package settings, etc. - -When you develop a package for Umbraco Cloud there are a few things to be aware of when storing data, mainly whether you want that data to be specific to 1 environment or more. - -Let's take a look at the most common ways of storing data in packages - and what to watch out for on Cloud. - -### Migrations - -A [migration](../database.md) is some code that you run as part of a migration plan. That migration plan has an ID that is stored in the database (in the KeyValue table). This means that when you add new migrations Umbraco will only execute the ones that came after the one with the stored ID. The most important difference between a migration and a package action is when they are initialized. A package action runs on package install and uninstall, whereas a migration will run whenever you want it to run, see below for common examples. - -As migration runs are stored in the database of the site it also means that they will run on each environment you trigger them on. The most common way to trigger a migration is to include them in a [composer](../../implementation/composing.md), which will ensure they run on site startup. This means any commands you have in your migration will automatically run when the site starts up. When your package code is pushed to a new environment it will run them from the beginning on that environment as no ID is saved in the database. - -This is normally a good thing. However if you generate any Umbraco schema then Umbraco Deploy will automatically create [UDA files](https://docs.umbraco.com/umbraco-cloud/set-up/power-tools/generating-uda-files#generate-uda-files-manually) based on that schema, and commit them to source control. This means that when you deploy all your files to the next environment the migration will run again, create duplicates and generate duplicate UDA files, which could end up causing a lot of issues. - -You could consider creating Umbraco schema only during a package action, and then running things like creating database tables in migrations. Another good workaround could be to not run the migrations in a composer, but rather create a dashboard for the package where the user can choose which migrations to run themselves. The [Articulate package](https://github.com/Shazwazza/Articulate/blob/master/build/packageManifest.xml#L613) has an example of this. - -### Creating files - -You may sometimes choose to save data in a file. Could be a separate config file for your package or a [config transform file](https://docs.umbraco.com/umbraco-cloud/set-up/config-transforms) to add an app setting to the web.config. If you do this be aware of two things: - -1. If these files are generated on a Cloud environment they will not be stored in source control, and will be overwritten on next deployment. They need to be installed locally, committed to source control and then pushed up to the Cloud environments. We have an [existing feature request](https://github.com/umbraco/Umbraco.Cloud.Issues/issues/33) on allowing package creators to commit their files directly on Cloud, and it is possible to do so currently but not in a supported way, and it may change suddenly. -2. If you need the content of the files to be different on the different environments you will need to use environment specific [config transforms](https://docs.umbraco.com/umbraco-cloud/set-up/config-transforms). - -## Value connectors - -A value connector is an extension to Umbraco Deploy that allows you to transform data when you deploy content of any kind between environments. When it comes to packages, one reason you need to consider these if you are supporting deploying content properties that rely on integer IDs. Content and other Umbraco data has two identifiers - an integer and a GUID. The GUID is consistent between environments but the integer ID is not. As such, if transferring content between environments and relying on integer IDs, you'll need to include a value connector to transform the value. - -They also manage dependencies for property data. If you save an ID of an image in your property editor, you can make sure the related image media item is transferred too. - -You can read more about value connectors and other extensions to Umbraco Deploy [here](https://docs.umbraco.com/umbraco-deploy/v/10.deploy.latest/getting-started/extending). \ No newline at end of file diff --git a/10/umbraco-cms/extending/packages/types-of-packages.md b/10/umbraco-cms/extending/packages/types-of-packages.md deleted file mode 100644 index 1a56fac9f32..00000000000 --- a/10/umbraco-cms/extending/packages/types-of-packages.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -description: >- - Depending on which version of Umbraco CMS you are using, we distinguish - between two package types, NuGet packages, and Package ZIP files. ---- - -# Package Types - -Packages for Umbraco 10 and above are installed as NuGet packages. - -{% hint style="warning" %} -The legacy, zip file package type is only available for Umbraco version 8 and earlier versions. Learn more about it in the [Package zip Files](types-of-packages.md#package-zip-files) section of this article. -{% endhint %} - -## NuGet Packages - -A NuGet package is a standard way of delivering compiled code and configuration to a .NET project. NuGet packages contain dll-files and other files required for the solution. For more information on NuGet packages see Microsoft's [An introduction to NuGet](https://docs.microsoft.com/en-us/nuget/what-is-nuget) documentation. - -NuGet packages can be installed using via the command line or through Visual Studio using either the [Package Manager Console](https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-powershell) or the [NuGet Package Manager](https://learn.microsoft.com/en-us/nuget/consume-packages/install-use-packages-visual-studio). - -See below, for an example of installing a package using the Package Manager Console in Visual Studio: - -```powershell -PM> Install-Package MyPackage -version 1.2 -``` - -NuGet packages can include any solution files and can be configured to run PowerShell scripts after installation. - -As NuGet packages are installed outside of the Umbraco website they cannot directly manipulate any of the Umbraco settings or content during their installation. - -When adding or changing configuration of Umbraco as part of a NuGet package you need to develop code to run as part of a [Migration](../database.md). The Migration will run the first time the Umbraco site starts after the package is installed, applying the correct configuration. - -## Package zip files - -{% hint style="warning" %} -Zip file packages are only available for Umbraco CMS 8 and earlier versions. - -Refer to the [NuGet Packages](types-of-packages.md#nuget-packages) section above, if your website is using Umbraco 10 or a later version. -{% endhint %} - -A package zip file can be installed directly through the Umbraco backoffice. - -![Zip packages can be installed via the Umbraco backoffice package section]() - -Packages zip files can contain: - -* Content -* Solutions files (`dll`s, `App_Plugins` files, etc) -* Document Types -* Templates -* Stylesheets -* Macros -* Languages -* Dictionary Items -* Data Types -* Media - -{% hint style="info" %} -To include media in your package, select it in the "Media" section. Additionally, choose it in the "Package Files" section under "Path to file." -{% endhint %} diff --git a/10/umbraco-cms/extending/property-editors/README.md b/10/umbraco-cms/extending/property-editors/README.md deleted file mode 100644 index 460cc75a115..00000000000 --- a/10/umbraco-cms/extending/property-editors/README.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: "Guide on how to work with and create Property Editors in Umbraco" ---- - -# Property Editors - -This section describes how to work with and create Property Editors. A property editor is the editor used to insert content into Umbraco. [See here for definition](../../fundamentals/backoffice/property-editors/) - -## Tutorials - Creating a property editor - -* [Creating a property editor](../../tutorials/creating-a-property-editor/) -* [Adding configuration to a property editor](../../tutorials/creating-a-property-editor/part-2.md) -* [Integrating services with a property editor](../../tutorials/creating-a-property-editor/part-3.md) -* [Adding server side data to a property editor](../../tutorials/creating-a-property-editor/part-4.md) - -## [Package Manifest](package-manifest.md) - -Reference for the package.manifest JSON file format to register one or more property editors for Umbraco. - -## [Property Value Converters](property-value-converters.md) - -Convert the stored property data value to a useful object returned by the Published Content APIs. - -## [Property Actions](property-actions.md) - -Use Property Actions to add additional functionality to your custom property editors. - -## [Tracking References](tracking.md) - -Learn how to extend Property editors to track entity references inside the property editor. - -## More information - -* [Built in Property Editors](../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/) diff --git a/10/umbraco-cms/extending/property-editors/declaring-your-property-editor.md b/10/umbraco-cms/extending/property-editors/declaring-your-property-editor.md deleted file mode 100644 index dd2fd5731aa..00000000000 --- a/10/umbraco-cms/extending/property-editors/declaring-your-property-editor.md +++ /dev/null @@ -1,335 +0,0 @@ -# Declaring your property editor - -Generally Umbraco supports two different ways to declare a property editor. Most commonly one would create a `package.manifest` file, and then use it for declaring one or more property editors. But as an alternative, property editors can also be declared using C#. - -A property editor consists of a number of mandatory properties, and some optional ones as well. As such, the outer JSON object for the property editor has the following properties: - -| Name | Type | Required | Description | -| ------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `alias` | string | Yes | A unique alias that identifies the property editor. | -| `name` | string | Yes | The friendly name of the property editor, shown in the Umbraco backoffice. | -| `editor` | object | Yes | This describes details about the editor. See the table below for further information. | -| `icon` | string | No | A CSS class for the icon to be used in the **Select Editor** dialog - eg: `icon-autofill`. | -| `group` | string | No | The group to place this editor in within the **Select Editor** dialog. Use a new group name or alternatively use an existing one such as **Pickers**. | -| `isParameterEditor` | boolean | No | Enables the property editor as a macro parameter editor. Can be either `true` or `false` (default). | -| `defaultConfig` | object | No | Provides a collection of default configuration values, in cases the property editor is not configured or is used a parameter editor (which doesn't allow configuration). The object is a key/value collection and must match the prevalue fields keys. | - -The `editor` object then has the following properties: - -| Name | Type | Required | Description | -| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `view` | string | Yes | This is the full path to the HTML view for your property editor. | -| `hideLabel` | bool | Yes | If set to `true`, this hides the label for the property editor when used in Umbraco on a Document Type. | -| `valueType` | object | No | This is the type of data you want your property editor to save to Umbraco. Possible values are `STRING`, `JSON`, `DATETIME`, `TEXT` and `INT`. Default is `STRING`. | -| `validation` | object | No | Object describing required validators on the editor. | -| `isReadOnly` | boolean | No | If set to true this makes the property editor read only. | - -## Using a Package Manifest - -A package manifest is a file specific to your package or custom code. This file is always stored in a folder in `/App_Plugins/{YourPackageName}`, and with the name `package.manifest` : - -```json -{ - "propertyEditors": [ - { - "alias": "Sir.Trevor", - "name": "Sir Trevor", - "editor": { - "view": "/App_Plugins/SirTrevor/SirTrevor.html", - "hideLabel": true, - "valueType": "JSON" - } - } - ], - "javascript": [ - "/App_Plugins/SirTrevor/SirTrevor.controller.js" - ] -} -``` - -This example manifest specifies a **Sir Trevor** property editor via the `propertyEditors` collection, and also adds a single JavaScript file via the `javascript` property. - -The actual **Sir Trevor** property editor has some additional configuration. It's a block based editor, so for instance it has a prevalue for setting the maximum amount of blocks allowed. In full, the `package.manifest` file for the Sir Trevor package looks like: - -```json -{ - "propertyEditors": [ - { - "alias": "Sir.Trevor", - "name": "Sir Trevor", - "editor": { - "view": "/App_Plugins/SirTrevor/SirTrevor.html", - "hideLabel": true, - "valueType": "JSON" - }, - "prevalues": { - "fields": [ - { - "label": "Maximum number of blocks", - "description": "The total maximum number of blocks (of any type) that can be displayed (0 = infinite).", - "key": "blockLimit", - "view": "requiredfield", - "validation": [ - { - "type": "Required" - } - ] - }, - { - "label": "Align editor centered", - "description": "If the editor doesn't span the entire width of the content editing area, center it. Otherwise left aligned.", - "key": "editorAlignCentered", - "view": "boolean" - }, - { - "label": "Editor width", - "description": "The width the Sir Trevor editor will expand to, most likely 100%.", - "key": "editorWidth", - "view": "requiredfield", - "validation": [ - { - "type": "Required" - } - ] - }, - { - "label": "Maximum editor width", - "description": "The maximum width the Sir Trevor editor will expand to, i.e. 500px or 80%.", - "key": "editorMaxWidth", - "view": "requiredfield", - "validation": [ - { - "type": "Required" - } - ] - }, - { - "label": "Block types", - "description": "Configure the block types available to the user.", - "key": "blocktypes", - "view": "~/App_Plugins/SirTrevor/settings/blocktypes.html" - } - ] - } - } - ], - "javascript": [ - "/App_Plugins/SirTrevor/SirTrevor.controller.js", - "/App_Plugins/SirTrevor/settings/settings.blocktypes.controller.min.js", - "/App_Plugins/SirTrevor/settings/settings.resource.min.js" - ] -} -``` - -## Using Csharp - -The same property editor can be declared using C# instead using the `DataEditor` class and decorating the class with the `DataEditor` attribute: - -```csharp -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.WebAssets; -using Umbraco.Cms.Infrastructure.WebAssets; - -namespace UmbracoEightExamples.PropertyEditors -{ - [DataEditor( - "Sir.Trevor", - EditorType.PropertyValue, - "Sir Trevor", - "/App_Plugins/SirTrevor/SirTrevor.html", - ValueType = ValueTypes.Json, - HideLabel = true)] - [PropertyEditorAsset(AssetType.Javascript, "/App_Plugins/SirTrevor/SirTrevor.controller.js")] - public class SirTrevorEditor : DataEditor - { - public SirTrevorEditor( - IDataValueEditorFactory dataValueEditorFactory, - EditorType type = EditorType.PropertyValue) - : base(dataValueEditorFactory, type) - { - } - } -} -``` - -Also notice how the `PropertyEditorAsset` attribute is used to load the `SirTrevor.controller.js` JavaScript file. - -### DataEditor attribute - -The [DataEditor](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.PropertyEditors.DataEditorAttribute.html) attribute shown in the example above is the primary component to declaring the property editor in C#. Notice that the first four properties must be set through the constructor. - -| Name | Type | Required | Description | -| -------------- | --------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- | -| `Alias` | string | Yes | Gets the unique alias of the editor. | -| `EditorType` | [EditorType](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.PropertyEditors.EditorType.html) | Yes | Gets the type of the editor. Possible values are `EditorType.PropertyValue`, `EditorType.MacroParameter` or `EditorType.Nothing`. | -| `Name` | string | Yes | Gets the friendly name of the editor. | -| `View` | string | Yes | Gets the view to use to render the editor. | -| `ValueType` | string | No | Gets or sets the type of the edited value. | -| `HideLabel` | boolean | No | Gets or sets a value indicating whether the editor should be displayed without its label. | -| `Icon` | string | No | Gets or sets an optional icon. | -| `Group` | string | No | Gets or sets an optional group. | -| `IsDeprecated` | boolean | No | Gets or sets a value indicating whether the value editor is deprecated. | - -### PropertyEditorAsset attribute - -As shown in the C# example, the [PropertyEditorAsset](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Infrastructure.WebAssets.PropertyEditorAssetAttribute.html) attribute was used to make Umbraco load the specified JavaScript file. - -The constructor of the attribute takes the type of the assets as the first parameter. Possible values are either `AssetType.Javascript` or `AssetType.Css`. The second parameter is the URL of the asset. - -### DataEditor class - -In the example above, the `SirTrevorEditor` class doesn't really do much. For more basic property editors, the C# approach may require a bit more work compared to that of `package.manifest` files. But as property editors grow in complexity, using C# becomes a bit more useful - and also lets you do things not possible with `package.manifest` files. - -The [DataEditor](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.PropertyEditors.DataEditor.html) class defines a virtual `CreateConfigurationEditor` method. It returns a model which is used for the Angular view when editing the prevalues of a Data Type. - -Virtual methods are methods declared in a parent class. These methods have a default implementation that can be overridden in classes that inherit from the parent class. For instance in the example below, we can override the method and provide our own `SirTrevorConfigurationEditor` instead of what Umbraco returns by default. - -```csharp -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.WebAssets; -using Umbraco.Cms.Infrastructure.WebAssets; - -namespace UmbracoEightExamples.PropertyEditors -{ - [DataEditor( - "Sir.Trevor", - EditorType.PropertyValue, - "Sir Trevor", - "/App_Plugins/SirTrevor/SirTrevor.html", - ValueType = ValueTypes.Json, - HideLabel = true)] - [PropertyEditorAsset(AssetType.Javascript, "/App_Plugins/SirTrevor/SirTrevor.controller.js")] - public class SirTrevorEditor : DataEditor - { - public SirTrevorEditor( - IDataValueEditorFactory dataValueEditorFactory, - EditorType type = EditorType.PropertyValue) - : base(dataValueEditorFactory, type) - { - } - - protected override IConfigurationEditor CreateConfigurationEditor() => new SirTrevorConfigurationEditor(); - - } -} -``` - -In this case, the `SirTrevorConfigurationEditor` class doesn't do much either - but notice that it inherits from `ConfigurationEditor`, meaning the configuration will be of type `SirTrevorConfiguration`: - -```csharp -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Services; - -namespace UmbracoEightExamples.PropertyEditors -{ - public class SirTrevorConfigurationEditor : ConfigurationEditor - { - public SirTrevorConfigurationEditor(IIOHelper ioHelper, IEditorConfigurationParser editorConfigurationParser) : base(ioHelper, editorConfigurationParser) - { - } - } -} -``` - -The referenced `SirTrevorConfiguration` class is then what declares the configuration fields of when editing a Data Type using the Sir Trevor property editor: - -```csharp -using Umbraco.Cms.Core.PropertyEditors; - -namespace UmbracoEightExamples.PropertyEditors -{ - public class SirTrevorConfiguration - { - [ConfigurationField("blockLimit", "Maximum number of blocks", "requiredfield", - Description = "The total maximum number of blocks (of any type) that can be displayed (0 = infinite).")] - public int BlockLimit { get; set; } - - [ConfigurationField("editorAlignCentered", "Align editor centered", "boolean", - Description = - "If the editor doesn't span the entire width of the content editing area, center it. Otherwise left aligned.")] - public bool EditorAlignCentered { get; set; } - - [ConfigurationField("editorWidth", "Editor width", "requiredfield", - Description = "The width the Sir Trevor editor will expand to, most likely 100%.")] - public int EditorWidth { get; set; } - - [ConfigurationField("editorMaxWidth", "Maximum editor width", "requiredfield", - Description = "The maximum width the Sir Trevor editor will expand to, i.e. 500px or 80%.")] - public int EditorMaxWidth { get; set; } - - [ConfigurationField("blocktypes", "Block types", "/App_Plugins/SirTrevor/settings/blocktypes.html", - Description = "Configure the block types available to the user.")] - public object BlockTypes { get; set; } - } -} -``` - -A benefit of this approach (opposed to `package.manifest` files) is that we can now refer to the configuration using a strongly typed model - eg. as in this example Razor view: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@using Umbraco.Cms.Core.Services -@using UmbracoEightExamples.PropertyEditors -@inject IDataTypeService DataTypeService - -@{ - var dt = DataTypeService.GetDataType(1234); - - if (dt is not null) - { -
@dt.Name
- -
@(dt.Configuration as SirTrevorConfiguration)
- -
@(dt.ConfigurationAs())
- } -} -``` - -Both instances of `IDataType` and `PublishedDataType` have a `Configuration` property. When looking across all data types and property editors, there is no common type for the configuration, so the return value is `object`. To get the strongly typed model, you can either cast the configuration value on your own, or use the generic `ConfigurationAs` extension method as shown above. - -Like mentioned before, the `SirTrevorConfigurationEditor` class doesn't really do much in this example with the Sir Trevor property editor. But the **Multi Node Tree Picker** and others of Umbraco's build in property editors also override the `ToValueEditor` method. - -This method is used when the strongly typed configuration value is converted to the model used by the Angular logic in the backoffice. So with the implementation of the [MultiNodePickerConfigurationEditor](https://github.com/umbraco/Umbraco-CMS/blob/ade9bb73246caf25a7073f2b9e5262641a201863/src/Umbraco.Web/PropertyEditors/MultiNodePickerConfigurationEditor.cs) class, some additional configuration fields are sent along. For instance that it's a multi picker and that the ID type should be URI's. These are configuration values that the user should not be able to edit, but the property editor may still rely on them. - -```csharp -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Services; - -namespace Umbraco.Cms.Core.PropertyEditors; - -/// -/// Represents the configuration for the multinode picker value editor. -/// -public class MultiNodePickerConfigurationEditor : ConfigurationEditor -{ - public MultiNodePickerConfigurationEditor(IIOHelper ioHelper, IEditorConfigurationParser editorConfigurationParser) - : base(ioHelper, editorConfigurationParser) => - Field(nameof(MultiNodePickerConfiguration.TreeSource)) - .Config = new Dictionary { { "idType", "udi" } }; - - /// - public override Dictionary ToConfigurationEditor(MultiNodePickerConfiguration? configuration) - { - // sanitize configuration - Dictionary output = base.ToConfigurationEditor(configuration); - - output["multiPicker"] = configuration?.MaxNumber > 1; - - return output; - } - - /// - public override IDictionary ToValueEditor(object? configuration) - { - IDictionary d = base.ToValueEditor(configuration); - d["multiPicker"] = true; - d["showEditButton"] = false; - d["showPathOnHover"] = false; - d["idType"] = "udi"; - return d; - } -} -``` diff --git a/10/umbraco-cms/extending/property-editors/full-examples-value-converters.md b/10/umbraco-cms/extending/property-editors/full-examples-value-converters.md deleted file mode 100644 index aa483f0cb9d..00000000000 --- a/10/umbraco-cms/extending/property-editors/full-examples-value-converters.md +++ /dev/null @@ -1,104 +0,0 @@ ---- - - ---- - -# Content Picker Value Converter Example - -```csharp -using System; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Extensions; - -namespace MyConverters -{ - public class ContentPickerPropertyConverter : IPropertyValueConverter - { - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - - //Injecting the PublishedSnapshotAccessor for fetching content - public ContentPickerPropertyConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor) - { - _publishedSnapshotAccessor = publishedSnapshotAccessor; - } - - public bool IsConverter(IPublishedPropertyType propertyType) - { - return propertyType.EditorAlias.Equals("Umbraco.ContentPicker"); - } - - public bool? IsValue(object value, PropertyValueLevel level) - { - switch (level) - { - case PropertyValueLevel.Source: - return value != null && (!(value is string) || string.IsNullOrWhiteSpace((string) value) == false); - default: - throw new NotSupportedException($"Invalid level: {level}."); - } - } - - public Type GetPropertyValueType(IPublishedPropertyType propertyType) - { - return typeof(IPublishedContent); - } - - public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - { - return PropertyCacheLevel.Elements; - } - - public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - { - if (source == null) return null; - - var attemptConvertInt = source.TryConvertTo(); - if (attemptConvertInt.Success) - return attemptConvertInt.Result; - - var attemptConvertUdi = source.TryConvertTo(); - if (attemptConvertUdi.Success) - return attemptConvertUdi.Result; - - return null; - } - - public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - { - if (inter == null) - return null; - - if ((propertyType.Alias != null) == false) - { - IPublishedContent content; - if (inter is int id) - { - content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(id); - if (content != null) - return content; - } - else - { - var udi = inter as GuidUdi; - if (udi == null) - return null; - content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(udi.Guid); - if (content != null && content.ContentType.ItemType == PublishedItemType.Content) - return content; - } - } - - return inter; - } - - public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - { - if (inter == null) return null; - return inter.ToString(); - } - } -} -``` diff --git a/10/umbraco-cms/extending/property-editors/images/JSON-schema.png b/10/umbraco-cms/extending/property-editors/images/JSON-schema.png deleted file mode 100644 index 70003504b6b..00000000000 Binary files a/10/umbraco-cms/extending/property-editors/images/JSON-schema.png and /dev/null differ diff --git a/10/umbraco-cms/extending/property-editors/images/data-types-references-v10.png b/10/umbraco-cms/extending/property-editors/images/data-types-references-v10.png deleted file mode 100644 index bc1cddf4a1c..00000000000 Binary files a/10/umbraco-cms/extending/property-editors/images/data-types-references-v10.png and /dev/null differ diff --git a/10/umbraco-cms/extending/property-editors/images/document-references-v9.png b/10/umbraco-cms/extending/property-editors/images/document-references-v9.png deleted file mode 100644 index ff428234d8e..00000000000 Binary files a/10/umbraco-cms/extending/property-editors/images/document-references-v9.png and /dev/null differ diff --git a/10/umbraco-cms/extending/property-editors/images/example-of-property-actions (1).jpg b/10/umbraco-cms/extending/property-editors/images/example-of-property-actions (1).jpg deleted file mode 100644 index 2e94865f559..00000000000 Binary files a/10/umbraco-cms/extending/property-editors/images/example-of-property-actions (1).jpg and /dev/null differ diff --git a/10/umbraco-cms/extending/property-editors/images/example-of-property-actions.jpg b/10/umbraco-cms/extending/property-editors/images/example-of-property-actions.jpg deleted file mode 100644 index 2e94865f559..00000000000 Binary files a/10/umbraco-cms/extending/property-editors/images/example-of-property-actions.jpg and /dev/null differ diff --git a/10/umbraco-cms/extending/property-editors/images/media-references-v9.png b/10/umbraco-cms/extending/property-editors/images/media-references-v9.png deleted file mode 100644 index 8cd405efa6b..00000000000 Binary files a/10/umbraco-cms/extending/property-editors/images/media-references-v9.png and /dev/null differ diff --git a/10/umbraco-cms/extending/property-editors/package-manifest.md b/10/umbraco-cms/extending/property-editors/package-manifest.md deleted file mode 100644 index 2239e5cb703..00000000000 --- a/10/umbraco-cms/extending/property-editors/package-manifest.md +++ /dev/null @@ -1,354 +0,0 @@ -# Package Manifest - -The `package.manifest` JSON file format is used to describe one or more custom Umbraco property editors, grid editors or parameter editors. This page outlines the file format and properties found in the JSON. - -## Sample Manifest - -This is a sample manifest, it is always stored in a folder in `/App_Plugins/{YourPackageName}`, with the name `package.manifest` - -```json -{ - "name": "Suggestions", - "version": "1.0.0 beta", - "allowPackageTelemetry": true, - "bundleOptions": "Default", - "packageView": "/App_Plugins/Suggestions/suggestion-config.html", - "propertyEditors": [ - { - "alias": "Suggestions", - "name": "Suggestions", - "editor": { - "view": "/App_Plugins/Suggestions/suggestion.html", - "hideLabel": true, - "valueType": "JSON", - "supportsReadOnly": true - } - } - ], - "javascript": [ - "/App_Plugins/Suggestions/suggestion.controller.js" - ] -} -``` - -## Sample Manifest with Csharp - -You can also register your files by implementing a `IManifestFilter` instead of creating a `package.manifest`. Create a `ManifestFilter.cs` file and implement the `IManifestFilter` interface. Then define the composer using the `IComposer` interface. - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Manifest; -using Umbraco.Cms.Core.PropertyEditors; - -namespace MyProject -{ - public class ManifestComposer : IComposer - { - //composer - public void Compose(IUmbracoBuilder builder) - { - builder.ManifestFilters().Append(); - } - } - public class ManifestFilter : IManifestFilter - { - private readonly IDataValueEditorFactory _dataValueEditorFactory; - - public ManifestFilter(IDataValueEditorFactory dataValueEditorFactory) - { - _dataValueEditorFactory = dataValueEditorFactory; - } - - public void Filter(List manifests) - { - manifests.Add(new PackageManifest - { - PackageName = "Suggestions", - Scripts = new[] - { - "/App_Plugins/Suggestions/suggestion.controller.js" - }, - Version = "1.0.0" - }); - } - } -} -``` - -{% hint style="info" %} - -For a functional example, you will need to register the editor and create the `HTML`, `JS`, and `CSS` files in the `App_Plugins/Suggestions` folder. You can find some examples of registering the editor in the `Suggestions.cs` file and within the files in the `App_Plugins` folder. For more information, see the [Creating a Property Editor article](https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-property-editor#setting-up-a-property-editor-with-csharp). - -{% endhint %} - -## Root elements - -The manifest can contain seven root collections, none of them are mandatory: - -```json -{ - "propertyEditors": [], - "gridEditors": [], - "parameterEditors": [], - "dashboards": [], - "sections": [], - "contentApps": [], - "javascript": [], - "css": [] -} -``` - -### Telemetry elements - -From version 9.2, some additional root elements were added. Their purpose is to control and facilitate telemetry for the package but none of these are mandatory. The properties are: - -* `name` - Allows you to specify a friendly name for your package that will be used for telemetry, if no name is specified the name of the folder will be used instead -* `version` - The version of your package, if this is not specified there will be no version specific information for your package -* `allowPackageTelemetry` - Allows you to entirely disable telemetry for your package if set to false, defaults to true. - -Example package.manifest - -```json -{ - "name": "My Awesome Package", - "version": "1.0.0", - "allowPackageTelemetry": true -} -``` - -## Property Editors - -`propertyEditors` returns an array of property editor definitions, each object specifies an editor to make available to data types as an editor component. These editors are primarily property editors for content, media and members. They can also be made available as a macro parameter editor. - -The basic values on any editor are `alias`, `name` and `editor`. These three **must** be set. Furthermore the editor value is an object with additional configuration options, it must contain a view value. - -```json -{ - "alias": "my.editor.alias", - "name": "My friendly editor name", - "editor": { - "view": "/App_Plugins/MyEditorName/view.html" - }, - "prevalues": { - "fields": [] - } -} -``` - -* `alias` The alias of the editor, this must be unique, its recommended to prefix with your own "namespace". -* `name` The name visible to the user in the UI, should also be unique. -* `editor` Object containing editor configuration (see below). -* `isParameterEditor` enables the property editor as a macro parameter editor can be `true`/`false`. -* `prevalues` Configuration of editor prevalues (see below). -* `defaultConfig` Default configuration values (see below). -* `icon` A CSS class for the icon to be used in the 'Select Editor' dialog: e.g. `icon-autofill`. -* `group` The group to place this editor in within the 'Select Editor' dialog. Use a new group name or alternatively use an existing one such as `Pickers`. -* `defaultConfig` Provides a collection of default configuration values, in case the property editor is not configured or is using a parameter editor, which doesn't allow configuration. The object is a key/value collection and must match the `prevalues` fields keys. - -### Editor - -`editor` Besides setting a view, the editor can also contain additional information. - -```json -"editor": { - "view": "/App_Plugins/MyEditorName/view.html", - "hideLabel": true, - "valueType": "TEXT", - "validation": {}, - "supportsReadOnly": true, - "isReadOnly": false -} -``` - -* `view` Path to the HTML file to use for rendering the editor. -* `hideLabel` Turn the label on or off by using `true` or `false`, respectively. -* `valueType` Sets the database type the value is stored as, by default it's `string`. -* `validation` Object describing required validators on the editor. -* `supportsReadOnly` Sets whether the editor supports read-only mode, if set to true, the editor is expected to have its own implementation of the read-only mode. -* `isReadOnly` Disables editing the value. - -`valueType` sets the kind of data the editor will save in the database, its default setting is `string`. The available options are: - -* `STRING` Stores the value as an nvarchar in the database -* `DATETIME` Stores the value as datetime in the database -* `TEXT` Stores the value as ntext in the database -* `INT` Stores the value as a bigint in the database -* `JSON` Stored as ntext and automatically serialized to a dynamic object - -### Pre Values - -`preValues` is a collection of prevalue editors, used for configuring the property editor, the prevalues object must return an array of editors, called `fields`. - -```json -"prevalues": { - "fields": [ - { - "label": "Enable something", - "description": "This is a description", - "key": "enableStuff", - "view": "boolean" - } - ] -} -``` - -Each field contains a number of configuration values: - -* `label` The label shown on the Data Type configuration screen -* `description` Help text displayed underneath the label -* `key` The key the prevalue is stored under (see below) -* `view` Path to the editor used to configure this prevalue (see below) - -`key` on a prevalue, determines where it's stored in the database. If you give your prevalue the key "wolf" then this key will be used in the prevalue table. - -It also means when this property editor is used on a property, the prevalue will be exposed on the model's configuration object. This occurs inside the property editor's controller, as shown below: - -```javascript -// this is the property value -$scope.model.value = "hello"; - -// this is the configuration on the property editor -$scope.model.config - -// this is our specific prevalue with the alias wolf -$scope.model.config.wolf -``` - -`view` config value points the prevalue editor to an editor to use. This follows the same concept as any other editor in Umbraco, but with prevalue editors there are a couple of conventions. - -If you specify a name like `boolean` then Umbraco will look at `/wwwroot/umbraco/views/prevalueeditors/boolean/boolean.html` for the editor view. If you wish to use your own, you specify the path like `/App_Plugins/{YourPackageName}/prevalue-editor.html`. - -### Default Config - -The defaultConfig object provides a collection of default configuration values in case the property editor is not configured or is using a parameter editor. This object is a key/value collection and must match the prevalue field keys. - -```json -"defaultConfig": { - "wolf": "nope", - "editor": "hello", - "random": 1234 -} -``` - -## Grid Editors - -Similar to how the `propertyEditors` array defines one or more property editors, `gridEditors` can be used to define editors specific to the grid. Setting up the default richtext editor in the Umbraco grid could look like: - -```json -{ - "gridEditors": [ - { - "name": "Rich text editor", - "alias": "rte", - "view": "rte", - "icon": "icon-article" - } - ] -} -``` - -However the default grid editors are already configured. You can see the [Grid Editors page](../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors.md) for more information on grid editors. - -## Parameter Editors - -`parameterEditors` returns an array of editor objects, each object specifies an editor to make available to macro parameters as an editor component. These editors work solely as parameter editors and will not show up on the property editors list. - -The parameter editors array follows the same format as the property editors described above. However, it cannot contain prevalues since there are no configuration options for macro parameter editors. - -## JavaScript - -`javascript` returns a string\[] of JavaScript files to load on application start - -```json -{ - "javascript": [ - "/App_Plugins/MyEditorName/MyEditorName.controller.js", - "/App_Plugins/MyEditorName/MyEditorName.js" - ] -} -``` - -## CSS - -`css` returns a string\[] of css files to load on application start - -```json -{ - "css": [ - "/App_Plugins/MyEditorName/MyEditorName.css", - "/App_Plugins/MyEditorName/hibba.css" - ] -} -``` - -## Bundling - -`bundleOptions` is an enumerable type that expects one of the following values: - -* `Default` - The default bundling behavior for assets in the package folder where the assets will be bundled with the typical packages bundle. -* `None` - The assets in the package will not be processed at all and will all be requested as individual assets and will effectively be a bundle that has composite processing turned off for both debug and production. -* `Independent` - The packages assets will be processed as its own separate bundle. (In debug, files will not be processed) - -## JSON Schema - -The package.manifest JSON file has a hosted online JSON schema file. This allows editors such as Visual Studio, Rider, and Visual Studio Code to have autocomplete/intellisense support when creating and editing package.manifest files. This helps to avoid mistakes or errors when creating your package.manifest files. - -### Setting up Visual Studio 2015+ - -To associate the hosted JSON schema file to all package.manifest files you will need to perform the following inside of Visual Studio 2015. - -* Tools -> Options -* Browse down to Text Editor -> File Extension -* Add `manifest` into the Extension box -* Select `JSON Editor` from the dropdown and add the mapping -* Open a `package.manifest` file and ensure in the top left hand corner you see the schema with the URL set to `http://json.schemastore.org/package.manifest`. You can also add the schema inline in the json file (see below). - -### Setting up JetBrains Rider 2019+ - -To associate the hosted JSON schema file to all package.manifest files you will need to perform the following inside of Visual Studio 2015. - -* File -> Settings -* Browse down to Editor -> File Types -> JSON -* Add `package.manifest` to the list of file pattern names. -* Browse down to Languages & Frameworks -> Schemas and DTDs -> JSON Schema Mappings -* Add new by clicking the `+` symbol -* Add `package.manifest` as Name -* Add `https://json.schemastore.org/package.manifest` as the Schema File or URL, or choose `package.manifest` from the Remote Schema URls -* Add `package.manifest` as File path pattern -* Open a `package.manifest` file and ensure in the bottom tool bar you see the schema is detected as `package.manifest`. - -### Setting up Visual Studio Code - -To associate the hosted JSON schema file to all package.manifest files you will need to perform the following inside of Visual Studio Code editor. - -* File -> Preferences -> Settings. The **Settings** window opens. -* In the **User** tab, go to **Extensions** -> **JSON** -> **Schemas**. - -
-* Select **Edit in settings.json** from the **Schemas** section. -* Add the following snippet in the `settings.json` file: - - ```json - { - "json.schemas": [ - { - "fileMatch": [ - "manifest.json" - ], - "url": "http://json.schemastore.org/package.manifest" - } - ] - } - ``` - -### Adding inline schema - -Editors like Visual Studio can use the `$schema` notation in your file. - -```json -{ - "$schema" : "http://json.schemastore.org/package.manifest", - "javascript": [], - "other properties": "" -} -``` diff --git a/10/umbraco-cms/extending/property-editors/property-actions.md b/10/umbraco-cms/extending/property-editors/property-actions.md deleted file mode 100644 index 90393f51f64..00000000000 --- a/10/umbraco-cms/extending/property-editors/property-actions.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -meta.Title: Umbraco Property Editors - Property Actions -description: Guide on how to implement Property Actions for Property Editors in Umbraco ---- - -# Property Actions - -Property Actions are a built-in feature that provide a generic place for secondary functionality for property editors. - -Property Actions appear as a small button next to the label of the property, which expands to show the available actions. They are defined and implemented in the Property Editor, making it open as to what a Property Action is. - -## Data Structure of Property Actions - -Property Editors are an array of objects defining each action. An action is defined by the following properties: - -```js -{ - labelKey: 'clipboard_labelForRemoveAllEntries', - labelTokens: [], - icon: 'trash', - method: removeAllEntries, - isDisabled: true -} -``` - -We use `labelKey` and `labelTokens` to retrieve a localized string that is displayed as the Actions label. [See localization for more info.](../language-files.md) - -`isDisabled` is used to disable an Action, which change the visual appearance and prevents interaction. Use this option when an action wouldn't provide any change. In the example above, the action `remove all entries` would not have any impact if there is no entries. - -## Implementation - -The implementation of Property Actions varies depending on whether your Property Editor is implemented with a Controller or as a Component. - -### Controller Implementation - -When your Property Editor is implemented with a Controller, use the following approach for the Property Action: - -```js -angular.module("umbraco").controller("My.MarkdownEditorController", function ($scope) { - -function myActionExecutionMethod() { - alert('My Custom Property Action Clicked'); - // Disable the action so it can not be re-run - // You may have custom logic to enable or disable the action - // Based on number of items selected etc... - myAction.isDisabled = true; -}; - -var myAction = { - labelKey: 'general_labelForMyAction', - labelTokens: [], - icon: 'action', - method: myActionExecutionMethod, - isDisabled: false -} - -var propertyActions = [ - myAction -]; - -this.$onInit = function () { - if ($scope.umbProperty) { - $scope.umbProperty.setPropertyActions(propertyActions); - } -}; - - -}); -``` - -### Component Implementation - -Follow this guide if your Property Editor is implemented as a Component. The Component must be configured to retrieve an optional reference to `umbProperty`. The requirement must be optional because property-editors are implemented in scenarios where it's not presented. - -See the following example: - -```js -angular.module('umbraco').component('myPropertyEditor', { - controller: MyController, - controllerAs: 'vm', - require: { - umbProperty: '?^umbProperty' - } - … -}); -``` - -See the following example for implementation of Property Actions in a Component, notice the difference is that we are parsing actions to `this.umbProperty.setPropertyActions(...)`. - -```js -var myAction = { - labelKey: 'general_labelForMyAction', - labelTokens: [], - icon: 'action', - method: myActionExecutionMethod, - isDisabled: false -} - -var propertyActions = [ - myAction -]; - -this.$onInit = function () { - if (this.umbProperty) { - this.umbProperty.setPropertyActions(propertyActions); - } -}; -``` diff --git a/10/umbraco-cms/extending/property-editors/property-value-converters.md b/10/umbraco-cms/extending/property-editors/property-value-converters.md deleted file mode 100644 index 005bf82f3c2..00000000000 --- a/10/umbraco-cms/extending/property-editors/property-value-converters.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -meta.Title: Umbraco Property Value Converters -description: A guide to creating a custom property value converter in Umbraco ---- - -# Property Value Converters - -A Property Value Converter converts a property editor's database-stored value to another type. The converted value can be accessed from MVC Razor or any other Published Content API. - -For example the standard Umbraco Core "Content Picker" stores a nodeId as `String` type. However if you implement a converter it could return an `IPublishedContent` object. - -Published property values have four "Values": - -* **Source** - The raw data stored in the database, this is generally a `String` -* **Intermediate** - An object of a type that is appropriate to the property, for example a nodeId should be an `Int` or a collection of nodeIds would be an integer array, `Int[]` -* **Object** - The object to be used when accessing the property using a Published Content API, for example UmbracoHelper's `GetPropertyValue` method -* **XPath** - The object to be used when the property is accessed by XPath; This should generally be a `String` or an `XPathNodeIterator` - -## Registering PropertyValueConverters - -PropertyValueConverters are automatically registered when implementing the interface. Any given PropertyEditor can only utilize a single PropertyValueConverter. - -If you are implementing a PropertyValueConverter for a PropertyEditor that doesn't already have one, creating the PropertyValueConverter will automatically enable it. No further actions are needed. - -If you aim to override an existing PropertyValueConverter, possibly from Umbraco or a package, additional steps are necessary. Deregister the existing one to prevent conflicts in this scenario. - -```csharp -using System.Linq; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -public class MyComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - //If the type is accessible (not internal) you can deregister it by the type: - builder.PropertyValueConverters().Remove(); - - //If the type is not accessible you will need to locate the instance and then remove it: - var contentPickerValueConverter = builder.PropertyValueConverters().GetTypes().FirstOrDefault(x => x.Name == "ContentPickerValueConverter"); - if (contentPickerValueConverter != null) - { - builder.PropertyValueConverters().Remove(contentPickerValueConverter); - } - } -} -``` - -The built-in PropertyValueConverters included with Umbraco, are currently marked as internal. This means you will not be able to remove them by type since the type isn't accessible outside of the namespace. In order to remove such PropertyValueConverters, you will need to look up the instance by name and then deregister it by the instance. This could be the case for other PropertyValueConverters included by packages as well, depending on the implementation details. - -## Implementing the Interface - -Implement `IPropertyValueConverter` from the `Umbraco.Cms.Core.PropertyEditors` namespace on your class - -```csharp -public class ContentPickerValueConverter : IPropertyValueConverter -``` - -## Methods - Information - -### IsConverter(IPublishedPropertyType propertyType) - -This method is called for each PublishedPropertyType (Document Type Property) at application startup. By returning `True` your value converter will be registered for that property type and your conversion methods will be executed whenever that value is requested. - -Example: Checking if the IPublishedPropertyType EditorAlias property is equal to the alias of the core content editor. This check is a string comparison but we recommend creating a constant for it to avoid spelling errors: - -```csharp -public bool IsConverter(IPublishedPropertyType propertyType) -{ - return propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.ContentPicker); -} -``` - -### IsValue(object value, PropertyValueLevel level) - -This method is called to determine if the passed-in value is a value, and is of the level specified. There's a basic implementation of this in `PropertyValueConverterBase`. - -### GetPropertyValueType(IPublishedPropertyType propertyType) - -This is where you can specify the type returned by this Converter. This type will be used by ModelsBuilder to return data from properties using this Converter in the proper type. - -Example: Content Picker data is being converted to `IPublishedContent`. - -```csharp -public Type GetPropertyValueType(IPublishedPropertyType propertyType) -{ - return typeof(IPublishedContent); -} -``` - -### PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - -Here you specify which level the property value is cached at. - -A property value can be cached at the following levels: - -#### `PropertyCacheLevel.Unknown` - -Do not use this cache level unless you know exactly what you're doing. We recommend using the `PropertyCacheLevel.Element` level. - -#### `PropertyCacheLevel.Element` - -The property value will be cached until its _element_ is modified. The element is what holds (or owns) the property. For example: - -* For properties used at the page level, the element is the entire page. -* For properties contained within Block List items, the element is the individual Block List item. - -This is the most commonly used cache level and should be your default, unless you have specific reasons to do otherwise. - -#### `PropertyCacheLevel.Elements` - -The property value will be cached until _any_ element (see above) is changed. This means that any change to any page will clear the property value cache. - -This is particularly useful for property values that contain references to other content or elements. For example, this cache level is utilized by the Content Picker to clear its property values from the cache upon content updates. - -#### `PropertyCacheLevel.Snapshot` - -The property value will only be cached for the duration of the current _snapshot_. - -A snapshot represents a point in time. For example, a snapshot is created for every content request from the frontend. When accessing a property in a snapshot using this cache level, it gets converted, cached throughout the snapshot, and later cleared. - -For all intents and purposes, think of this cache level as "per request". If your property value should _only_ be cached per request, this is the cache level you should use. Use it with caution, as the added property conversions incur a performance penalty. - -#### `PropertyCacheLevel.None` - -The property value will _never_ be cached. Every time a property value is accessed (even within the same snapshot) property conversion is performed explicitly. - -Use this cache level with extreme caution, as it incurs a massive performance penalty. - -```csharp -public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) -{ - return PropertyCacheLevel.Elements; -} -``` - -## Methods - Conversion - -There are a few different levels of conversion which can occur. - -### ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - -This method should convert the raw data value into an appropriate type. For example, a node identifier stored as a `String` should be converted to an `Int` or `Udi`. - -Include a `using Umbraco.Extensions;` to be able to use the `TryConvertTo` extension method. - -```csharp -public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) -{ - if (source == null) return null; - - var attemptConvertInt = source.TryConvertTo(); - if (attemptConvertInt.Success) - return attemptConvertInt.Result; - - var attemptConvertUdi = source.TryConvertTo(); - if (attemptConvertUdi.Success) - return attemptConvertUdi.Result; - - return null; -} -``` - -### ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - -This method converts the Intermediate to an Object. The returned value is used by the `GetPropertyValue` method of `IPublishedContent`. - -The below example converts the nodeId (converted to `Int` or `Udi` by _ConvertSourceToIntermediate_) into an 'IPublishedContent' object. - -```csharp -public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) -{ - if (inter == null) - return null; - - if ((propertyType.Alias != null && PropertiesToExclude.Contains(propertyType.Alias.ToLower(CultureInfo.InvariantCulture))) == false) - { - IPublishedContent content; - if (inter is int id) - { - content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(id); - if (content != null) - return content; - } - else - { - var udi = inter as GuidUdi; - if (udi == null) - return null; - content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(udi.Guid); - if (content != null && content.ContentType.ItemType == PublishedItemType.Content) - return content; - } - } - - return inter; -} -``` - -### ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - -This method converts the Intermediate to XPath. The return value should generally be of type `String` or `XPathNodeIterator`. - -In the example below, we convert the nodeId (converted by ConvertSourceToIntermediate) back into a `String`. - -```csharp -public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) -{ - if (inter == null) return null; - return inter.ToString(); -} -``` - -## Sample - -[Content Picker to `IPublishedContent` using `IPropertyValueConverter` interface](full-examples-value-converters.md) diff --git a/10/umbraco-cms/extending/property-editors/tracking.md b/10/umbraco-cms/extending/property-editors/tracking.md deleted file mode 100644 index fe03b096af9..00000000000 --- a/10/umbraco-cms/extending/property-editors/tracking.md +++ /dev/null @@ -1,152 +0,0 @@ ---- - - -meta.Title: Umbraco Property Editors - Tracking References -description: >- - Guide on how to implement tracking entity references for Property Editors in - Umbraco ---- - -# Tracking References - -Property editors can be extended further to track entity references that may be selected or referenced inside the property editor. For example in the core of the CMS we have added this to numerous property editors. - - -A good example of this is the Media Picker. The CMS stores a reference to the selected media item, enabling the identification of content nodes that use that particular media item. This avoids it being accidentally deleted if it is being used. - -When a content node is saved it will save the entity references as relations. - -## Viewing References - -### For Media Items - -1. Go to the **Media** section. -2. Select a media item and click the **Info** tab. - - ![Viewing media references](images/media-references-v9.png) - -### For Content Nodes - -1. Go to the **Settings** section. -2. Under the **Relation Types** folder, select **Related Document** relations and click **Relations**. - - ![Viewing document references](images/document-references-v9.png) - -### For Data Types - -1. Go to the **Settings** section. -2. Expand the **Data Types** folder. -3. Select the **Data Type** you wish to view the references -4. Navigate to the **Info** tab. - - ![Viewing Data Type references](images/data-types-references-v10.png) - -## Example - -The following example shows how to implement tracking for the inbuilt CMS property editor **Content Picker**. It will always add a specific media reference, regardless of what value is picked in the content picker. In your own implementations, you will need to parse the value stored from the property editor you are implementing. You will also need to find any references to picked items in order to track their references. - -{% tabs %} -{% tab title="Latest version" %} -```csharp -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Editors; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Extensions; - -namespace Umbraco.Web.PropertyEditors -{ - - public class ExampleComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.DataValueReferenceFactories().Append(); - } - } - - public class TrackingExample : IDataValueReferenceFactory, IDataValueReference - { - public IDataValueReference GetDataValueReference() => this; - - // Which Data Editor (Data Type) does this apply to - in this example it is the built in content picker of Umbraco - public bool IsForEditor(IDataEditor dataEditor) => dataEditor.Alias.InvariantEquals(Constants.PropertyEditors.Aliases.ContentPicker); - - - public IEnumerable GetReferences(object value) - { - // Value contains the raw data that is being saved for a property editor - // You can then analyse this data be it a complex JSON structure or something more trivial - // To add the chosen entities as references (as any UDI type including custom ones) - - // A very simple example - // This will always ADD a specific media reference to the collection list - // When it's a ContentPicker datatype - var references = new List(); - var udiType = ObjectTypes.GetUdiType(UmbracoObjectTypes.Media); - var udi = Udi.Create(udiType, Guid.Parse("fbbaa38d-bd93-48b9-b1d5-724c46b6693e")); - var entityRef = new UmbracoEntityReference(udi); - references.Add(entityRef); - return references; - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Editors; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Extensions; - -namespace Umbraco.Web.PropertyEditors -{ - - public class ExampleComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.DataValueReferenceFactories().Append(); - } - } - - public class TrackingExample : IDataValueReferenceFactory, IDataValueReference - { - public IDataValueReference GetDataValueReference() => this; - - // Which Data Editor (Data Type) does this apply to - in this example it is the built in content picker of Umbraco - public bool IsForEditor(IDataEditor? dataEditor) => dataEditor?.Alias == Constants.PropertyEditors.Aliases.ContentPicker; - - - public IEnumerable GetReferences(object? value) - { - // Value contains the raw data that is being saved for a property editor - // You can then analyse this data be it a complex JSON structure or something more trivial - // To add the chosen entities as references (as any UDI type including custom ones) - - // A very simple example - // This will always ADD a specific media reference to the collection list - // When it's a ContentPicker datatype - var references = new List(); - var udiType = ObjectTypes.GetUdiType(UmbracoObjectTypes.Media); - var udi = Udi.Create(udiType, Guid.Parse("fbbaa38d-bd93-48b9-b1d5-724c46b6693e")); - var entityRef = new UmbracoEntityReference(udi); - references.Add(entityRef); - return references; - } - } -} -``` -{% endtab %} -{% endtabs %} diff --git a/10/umbraco-cms/extending/section-trees/README.md b/10/umbraco-cms/extending/section-trees/README.md deleted file mode 100644 index 665128399c7..00000000000 --- a/10/umbraco-cms/extending/section-trees/README.md +++ /dev/null @@ -1,27 +0,0 @@ ---- - -meta.Title: "Umbraco Sections & Trees" -description: "An explanation on sections and trees in Umbraco" ---- - -# Sections & Trees - -The Umbraco backoffice consists of sections (sometimes referred to as applications) which contain Trees. - -Each section is identified by its name in the top navigation ribbon of the Umbraco Backoffice. - -For example, when you load the backoffice, you'll see that the 'Content' section contains one tree: the content tree. Meanwhile, the 'Settings' section contains a number of trees such as Stylesheets, Document Types, Media Types, etc... - -You can create your own sections and trees to extend Umbraco. - -## [Sections](sections.md) - -Describes Umbraco Sections, configuration and APIs. - -## [Trees](trees/) - -Describes Umbraco Trees, configuration, APIs and events. - -## [Searchable Trees (ISearchableTree)](searchable-trees.md) - -Explains how to customise the backoffice search of a Section Tree. diff --git a/10/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png b/10/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png deleted file mode 100644 index d5465050e54..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/add-custom-section-v8.png b/10/umbraco-cms/extending/section-trees/images/add-custom-section-v8.png deleted file mode 100644 index d5465050e54..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/add-custom-section-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/add-custom-section.png b/10/umbraco-cms/extending/section-trees/images/add-custom-section.png deleted file mode 100644 index 56ab633a134..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/add-custom-section.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png b/10/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png deleted file mode 100644 index 1ab9820f3bc..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/backoffice-search-v8.png b/10/umbraco-cms/extending/section-trees/images/backoffice-search-v8.png deleted file mode 100644 index 1ab9820f3bc..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/backoffice-search-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/backoffice-search.png b/10/umbraco-cms/extending/section-trees/images/backoffice-search.png deleted file mode 100644 index 31c5f536067..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/backoffice-search.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png b/10/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png deleted file mode 100644 index 6a8e9633af9..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/custom-section-alias-v8.png b/10/umbraco-cms/extending/section-trees/images/custom-section-alias-v8.png deleted file mode 100644 index 6a8e9633af9..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/custom-section-alias-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/custom-section-alias.png b/10/umbraco-cms/extending/section-trees/images/custom-section-alias.png deleted file mode 100644 index 9cac915a1cb..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/custom-section-alias.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png b/10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png deleted file mode 100644 index c1010a8dda1..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8.png b/10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8.png deleted file mode 100644 index c1010a8dda1..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/images/favouritethings-search.png b/10/umbraco-cms/extending/section-trees/images/favouritethings-search.png deleted file mode 100644 index 9b297a84ac5..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/images/favouritethings-search.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/searchable-trees.md b/10/umbraco-cms/extending/section-trees/searchable-trees.md deleted file mode 100644 index 601e1957546..00000000000 --- a/10/umbraco-cms/extending/section-trees/searchable-trees.md +++ /dev/null @@ -1,278 +0,0 @@ -# Searchable Trees (ISearchableTree) - -When you type a search term into the Umbraco backoffice search field, you'll see search results from all the Section Trees that your user account has permission to access: - -![Content Section Dashboards](<../../../../13/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png>) - -The results are grouped by 'Section Tree' like Content, Media, Document Types. Each 'Tree' has its own associated search mechanism that receives the search term and looks for matches in the tree that is responsible for searching. - -You can create your own search mechanisms for your own custom sections or replace the default search implementation for a particular section tree. - -## Custom Tree Search - -To create a search for your own custom tree you need to create a C# class that implements the interface `Umbraco.Cms.Core.Trees.ISearchableTree`. - -### ISearchableTree - -{% tabs %} -{% tab title="Latest version" %} -```csharp -using System.Collections.Generic; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Models.ContentEditing; - -namespace My.Website -{ - public interface ISearchableTree : IDiscoverable - { - /// - /// The alias of the tree that the belongs to - /// - string TreeAlias { get; } - - /// - /// Searches for results based on the entity type - /// - /// The search term used for finding matching results. - /// The number of records to return for a page of results. - /// The 0-based index for retrieving a page of search results. - /// Populated with the total number of results matching the provided search term. - /// - /// The starting point for the search, generally a node ID, but for members this is a member type alias. - /// - /// - Task SearchAsync(string query, int pageSize, long pageIndex, string? searchFrom = null); - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -using System.Collections.Generic; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Models.ContentEditing; - -namespace My.Website -{ - public interface ISearchableTree : IDiscoverable - { - /// - /// The alias of the tree that the belongs to - /// - string TreeAlias { get; } - - /// - /// Searches for results based on the entity type - /// - /// The search term used for finding matching results. - /// The number of records to return for a page of results. - /// The 0-based index for retrieving a page of search results. - /// Populated with the total number of results matching the provided search term. - /// - /// The starting point for the search, generally a node ID, but for members this is a member type alias. - /// - /// - IEnumerable Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null); - } -} -``` -{% endtab %} -{% endtabs %} - -Your implementation needs to return an IEnumerable of `SearchResultEntity` items: - -{% tabs %} -{% tab title="Latest version" %} -```csharp -public class SearchResultEntity : EntityBasic -{ - public SearchResultEntity() { - /// - /// The score of the search result - /// - [DataMember(Name = "score")] - public float Score { get; set; } - }; - -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -public class SearchResultEntity : EntityBasic -{ - public SearchResultEntity(); - - /// - /// The score of the search result - /// - [DataMember(Name = "score")] - public float Score { get; set; } -} -``` -{% endtab %} -{% endtabs %} - -A `SearchResultEntity` consists of a Score (a Float value) identifying its relevance to the search term, and the set of `EntityBasic` properties that all Umbraco objects share: eg Name, Id, Udi, Icon, Trashed, Key, ParentId, Path, Alias, AdditionalData. - -#### Example implementation of ISearchableTree - -If we have a custom section Tree with the alias 'favouriteThingsAlias' (see the [custom tree example](trees/)) then we could implement searchability by creating the following C# class in our site: - -{% tabs %} -{% tab title="Latest version" %} -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.ContentEditing; -using Umbraco.Cms.Core.Trees; - -namespace Umbraco.Docs.Samples.Web.Trees -{ - public class FavouriteThingsSearchableTree : ISearchableTree - { - public string TreeAlias => "favouriteThingsAlias"; - - public async Task SearchAsync(string query, int pageSize, long pageIndex, string searchFrom = null) - { - // your custom search implementation starts here - Dictionary favouriteThings = new Dictionary(); - favouriteThings.Add(1, "Raindrops on Roses"); - favouriteThings.Add(2, "Whiskers on Kittens"); - favouriteThings.Add(3, "Skys full of Stars"); - favouriteThings.Add(4, "Warm Woolen Mittens"); - favouriteThings.Add(5, "Cream coloured Unicorns"); - favouriteThings.Add(6, "Schnitzel with Noodles"); - - var searchResults = new List(); - - var matchingItems = favouriteThings.Where(f => f.Value.StartsWith(query, true, System.Globalization.CultureInfo.CurrentCulture)); - foreach (var matchingItem in matchingItems) - { - // Making up the Id/Udi for this example! - these would normally be different for each search result. - searchResults.Add(new SearchResultEntity() - { - Id = 12345, - Alias = "favouriteThingItem", - Icon = "icon-favorite", - Key = new Guid("325746a0-ec1e-44e8-8f7b-6e7c4aab36d1"), - Name = matchingItem.Value, - ParentId = -1, - Path = "-1,12345", - Score = 1.0F, - Trashed = false, - Udi = Udi.Create("document", new Guid("325746a0-ec1e-44e8-8f7b-6e7c4aab36d1")) - }); - } - // Set number of search results found - var totalFound = matchingItems.Count(); - // Return your results - return new EntitySearchResults(searchResults, totalFound); - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.ContentEditing; -using Umbraco.Cms.Core.Trees; - -namespace Umbraco.Docs.Samples.Web.Trees -{ - public class FavouriteThingsSearchableTree : ISearchableTree - { - public string TreeAlias => "favouriteThingsAlias"; - - public IEnumerable Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null) - { - // your custom search implementation starts here - Dictionary favouriteThings = new Dictionary(); - favouriteThings.Add(1, "Raindrops on Roses"); - favouriteThings.Add(2, "Whiskers on Kittens"); - favouriteThings.Add(3, "Skys full of Stars"); - favouriteThings.Add(4, "Warm Woolen Mittens"); - favouriteThings.Add(5, "Cream coloured Unicorns"); - favouriteThings.Add(6, "Schnitzel with Noodles"); - - var searchResults = new List(); - - var matchingItems = favouriteThings.Where(f => f.Value.StartsWith(query, true, System.Globalization.CultureInfo.CurrentCulture)); - foreach (var matchingItem in matchingItems) - { - // Making up the Id/Udi for this example! - these would normally be different for each search result. - searchResults.Add(new SearchResultEntity() { - Id = 12345, - Alias = "favouriteThingItem", - Icon = "icon-favorite", - Key = new Guid("325746a0-ec1e-44e8-8f7b-6e7c4aab36d1"), - Name = matchingItem.Value, - ParentId = -1, - Path = "-1,12345", - Score = 1.0F, - Trashed = false, - Udi = Udi.Create("document", new Guid("325746a0-ec1e-44e8-8f7b-6e7c4aab36d1")) - }); - } - // Set number of search results found - totalFound = matchingItems.Count(); - // Return your IEnumerable of SearchResultEntity - return searchResults; - } - } -} -``` -{% endtab %} -{% endtabs %} - -That's all we need, after an application pool recycle, if we now search in the backoffice we'll see matches from our custom 'Favourite Things' tree: - -![Content Section Dashboards](<../../../../13/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png>) - -Umbraco automatically finds any implementation of `ISearchableTree` in your site and automatically configures it to be used for the custom section mentioned in the TreeAlias property. Be careful not to accidentally have two `ISearchableTree` implementations trying to search the 'same' TreeAlias, it's _one_ `ISearchableTree` per TreeAlias. - -## Replacing an existing Section Tree Search - -Perhaps you want to change the logic for searching an existing section of the site, (why? - well you might have a 'company name' property on a MemberType in the Member section, and you want searches for that company name to filter the members who work there, the default implementation will only search on Member Name). - -Or perhaps you want to replace Examine search in the backoffice with an external Search Service, e.g. Azure Search. In a cloud-hosted implementation you don't need to build the Examine indexes on each new server as your cloud hosting scales out. - -### Example - -First create your replacement custom `ISearchableTree` implementation, using the same approach as above, but specifying the TreeAlias of the Tree you aim to replace, e.g. 'Member'. - -```csharp -public string TreeAlias => "member"; -``` - -To avoid your custom implementation clashing with the default `ISearchableTree` for a Tree, you need to remove its `ISearchableTree` implementation from the collection of SearchableTrees using an `IComposer` when Umbraco starts up: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Web.BackOffice.Trees; - -namespace Umbraco.Docs.Samples.Web.Trees -{ - public class RemoveCoreMemberSearchableTreeComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Remove core MemberTreeController - builder.SearchableTrees().Exclude(); - } - } -} -``` - -This would then allow your custom implementation of `ISearchableTree` with TreeAlias 'member' to be used when searching the Member Section Tree. diff --git a/10/umbraco-cms/extending/section-trees/sections.md b/10/umbraco-cms/extending/section-trees/sections.md deleted file mode 100644 index 52c89332230..00000000000 --- a/10/umbraco-cms/extending/section-trees/sections.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -description: An explanation on sections and trees in Umbraco ---- - -# Sections - -The Umbraco backoffice consists of Sections, also referred to as Applications, which contain Trees. - -Each section is shown in the top navigation ribbon of the Umbraco Backoffice. - -## Create a Custom Section - -To create a new custom section in your Umbraco backoffice, the first thing you have to do is create a new folder inside `/App_Plugins`. We will call it `MyFavouriteThings`. - -Next we need to create a manifest where we'll include some basic configuration for our new section. - -## Registering a Custom Section - -There are two approaches to registering a custom section to appear in the Umbraco Backoffice: - -### Registering with package.manifest - -Create a new file in the `/App_Plugins/MyFavouriteThings/` folder and name it `package.manifest`. In this new file, copy the code snippet below and save it. - -```json -{ - "sections": [ - { - "alias": "myFavouriteThings", - "name": "My Favourite Things" - } - ] -} -``` - -This would create a new section in your Umbraco backoffice called 'My Favourite Things'. - -When registering your section this way, it is added to the end of the collection of sections. But as more `package.manifest` files may do the same, the order of the additional sections depends on the order of which the `package.manifest` files are loaded. Registering your section this way doesn't allow further control of its order. - -### Registering with C# Type - -By creating a C# class that implements `ISection` from `Umbraco.Cms.Core.Sections`: - -```csharp -using Umbraco.Cms.Core.Sections; - -namespace My.Website.Sections; - -public class MyFavouriteThingsSection : ISection -{ - public string Alias => "myFavouriteThings"; - - public string Name => "My Favourite Things"; -} -``` - -For your C# type to be discovered by Umbraco at application start up, it needs to be appended to the `SectionCollectionBuilder`. - -You can achieve this by creating a `Composer` and call the `Append` method: - -```csharp -using Umbraco.Cms.Core.Composing; - -namespace My.Website.Sections; - -public class SectionComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.Sections().Append(); - } -} -``` - -This would also create a new section called 'My Favourite Things' in your Umbraco Backoffice. - -Similar to registering the section via a `package.manifest` file, the `Append<>` method will add the section to the end of the list of sections. - -If you wish to control the order of your section a bit more, you can use some of the other methods on `SectionsCollectionBuilder`. For instance, you can add your section at a specific index: - -```csharp -builder.Sections().Insert(2); -``` - -Or before or after an existing section: - -```csharp -builder.Sections().InsertBefore(); -``` - -```csharp -builder.Sections().InsertAfter(); -``` - -The final order of the sections is down to the order of which the composers are executed. For instance, two composers may add a new section before `SettingsSection`, in which case the latter will add its section between the section of the first composer and `SettingsSection`. - -### Why can't I see my new Custom Section? - -You will also need to allow your current Umbraco User group access to this new Custom Section via the backoffice! (you will need to logout and back in again to see the change) - -![Add Section for User](<../../../../13/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png>) - -### Adding a Language Translation (get rid of the square brackets) - -![Custom Section appears displaying Alias](<../../../../13/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png>) - -When your new custom section appears, you'll notice only the section 'Alias' is displayed inside square brackets. This is because Umbraco caters for Multiple Languages in the backoffice, and is looking for a translation file for the current backoffice culture, containing a translation key for your custom section alias. - -Create a /lang folder in the folder where you are creating the implementation for your custom section. If you do not have one already, create a `/lang` folder within the folder where you are creating the implementation for your custom section, eg. `/App_Plugins/MyFavouriteThings/lang/`. - -It is worth knowing that the `/lang` folder does not have to be directly in the MyFavouriteThings folder, it can be nested deeper if you need it to be. The only requirement is that the folder is called lang. E.g. _\~/App\_Plugins/MyFavouriteThings/Some/Another/Lang/_. - -Inside this folder create a file called **en-us.xml**. This is the 'default' fallback language translation file. Add the following definition: - -```xml - - - - My Favourite Things - - -``` - -Recycle the application pool, and the square brackets will be gone, and your section will have the title 'My Favourite Things'. - -You can add custom language translation keys in this file for providing translated versions of text used throughout your custom section/tree implementation. - -To provide translations in other languages, duplicate the en-us.xml file in the /lang folder and rename it to match the lang/culture combination of your newly supported language. Update the contents of the language element attributes, and provide a translation for each 'language translation key'. - -You will need to recycle the application pool, to see changes to the language translation files reflected in the backoffice. - -[Now create a custom tree to load in your custom section!](trees/) diff --git a/10/umbraco-cms/extending/section-trees/trees/README.md b/10/umbraco-cms/extending/section-trees/trees/README.md deleted file mode 100644 index 6fb2fc07b80..00000000000 --- a/10/umbraco-cms/extending/section-trees/trees/README.md +++ /dev/null @@ -1,403 +0,0 @@ ---- -meta.Title: Umbraco Tree -description: A guide to creating a custom tree in Umbraco ---- - -# Trees - -This section describes how to work with and create trees with Umbraco APIs. - -## Creating trees - -To Create a Tree in a section of the Umbraco backoffice, you need to take several steps: - -Create a `TreeController` class in C#. A new controller which inherits from the abstract `Umbraco.Cms.Web.BackOffice.Trees.TreeController`\*\` class and provides an implementation for two abstract methods: - -* GetTreeNodes (returns a `TreeNodeCollection`) - Responsible for rendering the content of the tree structure; -* GetMenuForNode (returns a `MenuItemCollection`) - Responsible for returning the menu structure to use for a particular node within a tree. - -You will need to add a constructor as `TreeController` requires this. See full code snippet in the "Implementing the Tree" section below. - -The `Tree` attribute used to decorate the `TreeController` has multiple properties. - -* `SectionAlias` - Alias of the section in which the tree appears -* `TreeAlias` - Alias of the tree -* `TreeTitle` - The title of the tree -* `TreeGroup` - The tree group, the tree belongs to -* `SortOrder` - Sort order of the tree - -For example: - -```csharp -[Tree("settings", "favouriteThingsAlias", TreeTitle = "Favourite Things Name", TreeGroup="favouritesGroup", SortOrder=5)] -public class FavouriteThingsTreeController : TreeController -{ } -``` - -The example above would register a custom tree with a title 'Favourite Things Name' in the Settings section of Umbraco, inside a custom group called 'Favourites'. - -### Tree Groups - -Tree Groups enable you to group trees in a section. You provide the alias of the Tree Group name, you wish to add your tree to - see [Constants.Trees.Groups](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Constants.Trees.Groups.html) for a list of existing group alias. An example of tree groups in the backoffice would be the _Settings_ tree group and the _Templating_ tree group in the _Settings_ section. - -If you add your own alias, you'll need to add a translation key. This can be done by adding a language file to a `lang` folder with your application folder in `App_Plugins`: `App_Plugins/favouriteThings/lang/en-us.xml`. This will avoid the alias appearing as the header in \[square brackets]. - -The language file should contain the following XML: - -```xml - - - Favourites - - -``` - -### Customising the Root Tree Node - -The first node in the tree is referred to as the **Root Node**. You can customise the Root Node by overriding the abstract `CreateRootNode` method. You can assign a custom icon to the Root Node. You can also specify a custom URL route path in the backoffice to use with your custom tree. The method can be useful if your section has a single node (single page app). - -[See Also: How to create your own custom section](../sections.md) - -### Implementing the Tree - -```csharp -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Actions; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Models.Trees; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Trees; -using Umbraco.Cms.Web.BackOffice.Trees; -using Umbraco.Extensions; - -namespace My.Website.Trees -{ - [Tree("settings", "favouriteThingsAlias", TreeTitle = "Favourite Things Name", TreeGroup = "favouritesGroup", SortOrder = 5)] - public class FavouriteThingsTreeController : TreeController - { - - private readonly IMenuItemCollectionFactory _menuItemCollectionFactory; - - public FavouriteThingsTreeController(ILocalizedTextService localizedTextService, - UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, - IMenuItemCollectionFactory menuItemCollectionFactory, - IEventAggregator eventAggregator) - : base(localizedTextService, umbracoApiControllerTypeCollection, eventAggregator) - { - _menuItemCollectionFactory = menuItemCollectionFactory ?? throw new ArgumentNullException(nameof(menuItemCollectionFactory)); - } - - protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) - { - var nodes = new TreeNodeCollection(); - - // check if we're rendering the root node's children - if (id == Constants.System.Root.ToInvariantString()) - { - // you can get your custom nodes from anywhere, and they can represent anything... - Dictionary favouriteThings = new Dictionary(); - favouriteThings.Add(1, "Raindrops on Roses"); - favouriteThings.Add(2, "Whiskers on Kittens"); - favouriteThings.Add(3, "Skys full of Stars"); - favouriteThings.Add(4, "Warm Woolen Mittens"); - favouriteThings.Add(5, "Cream coloured Unicorns"); - favouriteThings.Add(6, "Schnitzel with Noodles"); - - // loop through our favourite things and create a tree item for each one - foreach (var thing in favouriteThings) - { - // add each node to the tree collection using the base CreateTreeNode method - // it has several overloads, using here unique Id of tree item, - // -1 is the Id of the parent node to create, eg the root of this tree is -1 by convention - // - the querystring collection passed into this route - // - the name of the tree node - // - css class of icon to display for the node - // - and whether the item has child nodes - var node = CreateTreeNode(thing.Key.ToString(), "-1", queryStrings, thing.Value, "icon-presentation", false); - nodes.Add(node); - } - } - - return nodes; - } - - protected override ActionResult GetMenuForNode(string id, FormCollection queryStrings) - { - // create a Menu Item Collection to return so people can interact with the nodes in your tree - var menu = _menuItemCollectionFactory.Create(); - - if (id == Constants.System.Root.ToInvariantString()) - { - // root actions, perhaps users can create new items in this tree, or perhaps it's not a content tree, it might be a read only tree, or each node item might represent something entirely different... - // add your menu item actions or custom ActionMenuItems - menu.Items.Add(new CreateChildEntity(LocalizedTextService)); - // add refresh menu item (note no dialog) - menu.Items.Add(new RefreshNode(LocalizedTextService, true)); - } - else - { - // add a delete action to each individual item - menu.Items.Add(LocalizedTextService, true, opensDialog: true); - } - - return menu; - } - - protected override ActionResult CreateRootNode(FormCollection queryStrings) - { - var rootResult = base.CreateRootNode(queryStrings); - if (!(rootResult.Result is null)) - { - return rootResult; - } - - var root = rootResult.Value; - - // set the icon - root.Icon = "icon-hearts"; - // could be set to false for a custom tree with a single node. - root.HasChildren = true; - //url for menu - root.MenuUrl = null; - - return root; - } - } -} -``` - -![Favourite Things Custom Tree](../../../../../13/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png) - -### Responding to Tree Actions - -The actions on items in an Umbraco Tree will trigger a request to load an AngularJS view, with a name corresponding to the name of the action, from a subfolder of the views folder matching the name of the 'customTreeAlias'. - -Clicking on one of the 'Favourite Things' in the custom tree example will load an `edit.html` view from the folder: `/views/favouriteThingsAlias/edit.html`. The 'Delete' menu item would also load a view from: `/views/favouriteThingsAlias/delete.html` - -When creating a custom tree as part of a Umbraco package, it is recommended to change the location of the default folder. It should be changed to the `App_Plugins` folder. You achieve this by decorating your MVC `TreeController` with the `PluginController` attribute. - -```csharp -@using Umbraco.Cms.Web.Common.Attributes; - -[Tree("settings", "favouriteThingsAlias", TreeTitle = "Favourite Things Name")] -[PluginController("favouriteThings")] -public class FavouriteThingsTreeController : TreeController -{ } -``` - -The edit view in the example would now be loaded from the location: `/App_Plugins/favouriteThings/backoffice/favouriteThingsAlias/edit.html` - -#### Providing functionality in your Tree Action Views - -You can instruct the Umbraco backoffice to load additional JavaScript resources (eg. angularJS controllers) to use in conjunction with your 'tree action views' by adding a `package.manifest` file in the same folder location as your views. - -**For example**... - -```json -{ - "javascript": [ - "~/App_Plugins/favouriteThings/favouriteThings.resource.js", - "~/App_Plugins/favouriteThings/backoffice/favouriteThingsAlias/edit.controller.js", - "~/App_Plugins/favouriteThings/backoffice/favouriteThingsAlias/delete.controller.js" - ] -} -``` - -...this manifest would load files for two controllers to work with the edit and delete views and a general resource file, perhaps containing code to retrieve, create, edit and delete 'favourite things' from some external non-Umbraco API. - -Our Tree Action View would then be wired to the loaded controller using the `ng-controller` attribute. The delete view would perhaps the delete view look a little bit like this: - -```csharp -
-
-

- Are you sure you want to delete this favourite thing: {{currentNode.name}} ? -

- - -
-
-``` - -![Delete Raindrops on Roses](../../../../../13/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png) - -[see Tree Actions for a list of tree _ActionMenuItems_ and _IActions_](tree-actions.md) - -### Single Node Trees / Customising the Root Node Action - -It is possible to create 'trees' consisting of only a single node - perhaps to provide an area to control some settings or a placeholder for a single page backoffice app. See the LogViewer in the settings section for a good example. (or as in the case of the 'settings/content templates' tree, it's possible to have a custom view for the root node as an 'introduction' page to the tree). - -In both scenarios you need to override the `CreateRootNode` method for the custom tree. - -```csharp -[Tree("settings", "favouritistThingsAlias", TreeTitle = "Favourite Thing", TreeGroup = "favoritesGroup", SortOrder = 5)] -[PluginController("favouriteThing")] -public class FavouritistThingsTreeController : TreeController -{ } -``` - -You can override the `CreateRootNode` method to set the 'RoutePath' to where the single page application will live (or introduction page). Setting `HasChildren` to `false` will result in a Single Node Tree. - -```csharp -protected override ActionResult CreateRootNode(FormCollection queryStrings) -{ - var rootResult = base.CreateRootNode(queryStrings); - if (!(rootResult.Result is null)) - { - return rootResult; - } - - var root = rootResult.Value; - - //optionally setting a routepath would allow you to load in a custom UI instead of the usual behaviour for a tree - root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Settings, "favouritistThingsAlias", "overview"); - // set the icon - root.Icon = "icon-hearts"; - // set to false for a custom tree with a single node. - root.HasChildren = false; - //url for menu - root.MenuUrl = null; - - return root; -} -``` - -The RoutePath should be in the format of: **section/treeAlias/method**. As our example controller uses the `PluginController` attribute, clicking the root node would now request `/App_Plugins/favouriteThing/backoffice/favouritistThingsAlias/overview.html`. If you are not using the `PluginController` attribute, then the request would be to `/umbraco/views/favouritistThingsAlias/overview.html`. - -![Favourite Thing Custom Single Node Tree](../../../../../13/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png) - -#### Full Width App - IsSingleNodeTree - -It's possible to make your single node tree app stretch across the full screen of the backoffice (no navigation tree) - see Packages section for an example. To achieve this add an additional attribute `IsSingleNodeTree`, in the Tree attribute for the custom controller. - -```csharp -[Tree("settings", "favouritistThingsAlias", IsSingleNodeTree = true, TreeTitle = "Favourite Thing", TreeGroup = "favoritesGroup", SortOrder = 5)] -[PluginController("favouriteThing")] -public class FavouritistThingsTreeController : TreeController -{ } -``` - -## Tree notifications - -All tree notications are defined in the namespace `Umbraco.Cms.Core.Notifications`. - -For more information about registering and using notifications see [Notifications](../../../reference/notifications/) - -### RootNodeRenderingNotification - -The `RootNodeRenderingNotification` is published whenever a tree's root node is created. - -**Members:** - -* `TreeNode Node` -* `FormCollection QueryString` -* `string TreeAlias` - -**Usage:** - -```csharp -public void Handle(RootNodeRenderingNotification notification) -{ - // normally you will want to target a specific tree, this can be done by checking the tree alias - if (notification.TreeAlias.Equals("content")) - { - notification.Node.Name = "My new title"; - } -} -``` - -### TreeNodesRenderingNotification - -The `TreeNodesRenderingNotification` is published whenever a list of child nodes are created. - -**Members:** - -* `TreeNodeCollection Nodes` -* `FormCollection QueryString` -* `string TreeAlias` - -**Usage:** - -```csharp -using Umbraco.Cms.Core.Security; - -public class TreeNotificationHandler :INotificationHandler -{ - private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; - - public TreeNotificationHandler(IBackOfficeSecurityAccessor backOfficeSecurityAccessor) - { - _backOfficeSecurityAccessor = backOfficeSecurityAccessor; - } - - public void Handle(TreeNodesRenderingNotification notification) - { - // this example will filter any content tree node whose node name starts with - // 'Private', for any user that is in the customUserGroup - if (notification.TreeAlias.Equals("content") && - _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Groups.Any(f => - f.Alias.Equals("customUserGroupAlias"))) - { - notification.Nodes.RemoveAll(node => node.Name.StartsWith("Private")); - } - } -} -``` - -### MenuRenderingNotification - -The `MenuRenderingNotification` is raised whenever a menu is generated for a tree node. - -**Members:** - -* `MenuItemCollection Menu` -* `string NodeId` -* `FormCollection QueryString` -* `string TreeAlias` - -**Usage:** - -```csharp -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Security; - -public class TreeNotificationHandler : INotificationHandler -{ - private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; - - public TreeNotificationHandler(IBackOfficeSecurityAccessor backOfficeSecurityAccessor) - { - _backOfficeSecurityAccessor = backOfficeSecurityAccessor; - } - - public void Handle(MenuRenderingNotification notification) - { - // this example will add a custom menu item for all admin users - - // for all content tree nodes - if (notification.TreeAlias.Equals("content") && - _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Groups.Any(x => - x.Alias.InvariantEquals("admin"))) - { - // Creates a menu action that will open /umbraco/currentSection/itemAlias.html - var menuItem = new Umbraco.Cms.Core.Models.Trees.MenuItem("itemAlias", "Item name"); - - // optional, if you don't want to follow the naming conventions, but do want to use a angular view - // you can also use a direct path "../App_Plugins/my/long/url/to/view.html" - menuItem.AdditionalData.Add("actionView", "my/long/url/to/view.html"); - - // sets the icon to icon-wine-glass - menuItem.Icon = "wine-glass"; - // insert at index 5 - notification.Menu.Items.Insert(5, menuItem); - } - } -} -``` - -## Tree Actions and User Permissions - -[See a list of Tree Actions and User Permission Codes](tree-actions.md) diff --git a/10/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8 (1).png b/10/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8 (1).png deleted file mode 100644 index ac562758a4b..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png b/10/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png deleted file mode 100644 index ac562758a4b..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree (1).png b/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree (1).png deleted file mode 100644 index c40ceb25a75..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png b/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png deleted file mode 100644 index c40ceb25a75..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-tree-v8.png b/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-tree-v8.png deleted file mode 100644 index 9dcef2ad50c..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-tree-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8 (1).png b/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8 (1).png deleted file mode 100644 index c6e99e95dc7..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8 (1).png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png b/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png deleted file mode 100644 index c6e99e95dc7..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree.png b/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree.png deleted file mode 100644 index ada029e7947..00000000000 Binary files a/10/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree.png and /dev/null differ diff --git a/10/umbraco-cms/extending/section-trees/trees/tree-actions.md b/10/umbraco-cms/extending/section-trees/trees/tree-actions.md deleted file mode 100644 index 627987e8487..00000000000 --- a/10/umbraco-cms/extending/section-trees/trees/tree-actions.md +++ /dev/null @@ -1,93 +0,0 @@ ---- - - -meta.Title: "Umbraco Tree Actions" -description: "A guide to creating a custom tree action in Umbraco" ---- - -# Tree Actions - -Items in an Umbraco Tree can have associated Actions. The actions visible to the currently logged in user can be controlled via User Permissions. - -You can set a User's permissions for each item in the Umbraco Content tree from the User Section of the Umbraco Backoffice. - -If you are developing a custom section, or a custom Dashboard, you might want to display some different options based on a User's permission set on a particular item. - -For example, on a custom dashboard you might add a quick 'Create a Blog Post' button for an editor, but only if that editor has permissions to create a blog post. You could create some sort of API endpoint, to call from your AngularJS controller, that in turn uses the UserService to return the current user's permissions. Then you can see whether they have the required permission to 'create' within the site's blog section. - -```csharp -bool canCreateBlogs = false; -var user = _userService.GetByEmail(email); -var userPermissionsForBlog = _userService.GetPermissions(user, blogId); -foreach (var permission in userPermissionsForBlog) -{ - if (permission.AssignedPermissions.Contains("C")) - { - canCreateBlogs = true; - } -} -``` - -## But how to know which letter corresponds to which Tree Action? - -Each tree action in Umbraco implements the IAction interface, and each Action has a corresponding 'Letter', and a boolean value describing whether permissions can be assigned for an action. - -```csharp -public interface IAction : IDiscoverable -{ - char Letter {get;} - bool ShowInNotifier {get;} - bool CanBePermissionAssigned {get;} - string Icon {get;} - string Alias {get;} - string JsFunctionName {get;} - /// - /// A path to a supporting JavaScript file for the IAction. A script tag will be rendered out with the reference to the JavaScript file. - /// - string JsSource {get;} -} -``` - -When you pull back the AssignedPermissions for a user on a particular item, it is these letters that indicate which actions the User is permitted to perform in the context of the tree item. - -### User Permission Codes - -Here is a list of the tree actions and associated user permission codes shipped by Umbraco CMS and add-on projects (such as Umbraco Deploy), as well as those used by some community packages. - -If building a package or adding custom tree actions to your solution, it's important to pick a permission letter that doesn't clash with one of these. - -If you have created a package using a custom tree action, please consider providing an update to this documentation page via a PR to the [documentation repository](https://github.com/umbraco/UmbracoDocs), such that other developers can discover and avoid using the same permission letter. - -|Type|Alias|Letter|Can Be Permission Assigned| -|-|-|-|-| -|Umbraco.Cms.Core.Actions.ActionAssignDomain|assignDomain|I|True| -|Umbraco.Cms.Core.Actions.ActionBrowse|browse|F|True| -|Umbraco.Cms.Core.Actions.ActionCopy|copy|O|True| -|Umbraco.Cms.Core.Actions.ActionCreateBlueprintFromContent|createblueprint|ï|True| -|Umbraco.Cms.Core.Actions.ActionDelete|delete|D|True| -|Umbraco.Cms.Core.Actions.ActionMove|move|M|True| -|Umbraco.Cms.Core.Actions.ActionNew|create|C|True| -|Umbraco.Cms.Core.Actions.ActionNotify|notify|N|True| -|Umbraco.Cms.Core.Actions.ActionProtect|protect|P|True| -|Umbraco.Cms.Core.Actions.ActionPublish|publish|U|True| -|Umbraco.Cms.Core.Actions.ActionRestore|restore|V|False| -|Umbraco.Cms.Core.Actions.ActionRights|rights|R|True| -|Umbraco.Cms.Core.Actions.ActionRollback|rollback|K|True| -|Umbraco.Cms.Core.Actions.ActionSort|sort|S|True| -|Umbraco.Cms.Core.Actions.ActionToPublish|sendtopublish|H|True| -|Umbraco.Cms.Core.Actions.ActionUnpublish|unpublish|Z|True| -|Umbraco.Cms.Core.Actions.ActionUpdate|update|A|True| -|Umbraco.Deploy.UI.Actions.ActionDeployRestore|deployRestore|Q|True| -|Umbraco.Deploy.UI.Actions.ActionDeployTreeRestore|deployTreeRestore|Ψ|True| -|Umbraco.Deploy.UI.Actions.ActionPartialRestore|deployPartialRestore|Ø|True| -|Umbraco.Deploy.UI.Actions.ActionQueueForTransfer|deployQueueForTransfer|T|True| -|Umbraco.Deploy.UI.Actions.Export|deployExport|П|True| -|Umbraco.Deploy.UI.Actions.Import|deployImport|Џ|True| -|Jumoo.TranslationManager.Core.Actions.ActionTranslate|translate|5|True| -|Jumoo.TranslationManager.Core.Actions.ActionManageTranslation|manageTranslations|Ť|True| -|uSync.Publisher.Actions.PushToServer|pushContent|>|True| -|uSync.Publisher.Actions.PullFromServer|pullContent|<|True| -|uSync.Publisher.Action.PushButton|pushContentButton|^|True| -|Our.Umbraco.LinkedPages.LinkedAction|linkPages|l|True| - -*Note: up until Umbraco Deploy 9.2.0, the letter "N" was used for the "Queue For Transfer" action. In 9.2.1 it was changed to be "T", to avoid clashing with the letter selected for the Umbraco CMS "Notify" action, introduced in CMS version 8.18.* \ No newline at end of file diff --git a/10/umbraco-cms/extending/ui-library.md b/10/umbraco-cms/extending/ui-library.md deleted file mode 100644 index 8db0c6d650d..00000000000 --- a/10/umbraco-cms/extending/ui-library.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -description: A guide for getting started working with the Umbraco UI Library ---- - -# UI Library - -{% hint style="info" %} -The UI Library is currently _opt-in_. We recommend Backoffice and package developers start getting familiar with it. - -In the [Backoffice UI API Documentation](backoffice-ui-api-documentation.md) article you can find links to relevant resources for working with the Umbraco backoffice. -{% endhint %} - -The Umbraco UI Library is a set of web components that can be used to build Umbraco User Interfaces. The UI Library separates the user interface from Umbraco’s business logic and creates a unified user experience. This is done with coherent styling and naming, across all the Umbraco platforms and projects including the ones developed by you. - -With the UI Library, you get a collection of visual building blocks that consists of pieces to build any UI in Umbraco. Each component is a building block updating its display according to the data passed to it. - -## UI Library Storybook - -[Storybook](https://uui.umbraco.com/) is an application that gathers all the components together of the UI Library. It holds the documentation for the components and showcases different use case scenarios. You can explore all the components through stories reflecting their use cases. - -Each story has interactive controls that allows you to change the state of the component in real-time. Every publicly available property is editable in Storybook, so you can test out custom configurations and use-cases. - -You can also change the stylesheet of custom properties to see how the component will look like. Every story has a code example that you can copy and paste into your project. This will allow you to implement the components in your own packages and extensions. - -## Installing the UI Library Components - -You can download the UI Library package from [GitHub](https://github.com/umbraco/Umbraco.UI/tree/v1/contrib/packages). - -If you are installing a component via npm, there are two ways to import it: - -1. To import a specific component and register it at the same time, use the following command: - - ```sql - import '@umbraco-ui/uui-button/lib'; - ``` -2. To build on top of the components functionality, you can extend its class: - - ```sql - import { UUIButtonElement } from - '@umbraco-ui/uui-button/lib/uui-button.element'; - ``` - -For more information on installation, Content Delivery Networks (CDN), or included components, see the [Readme file in the GitHub](https://github.com/umbraco/Umbraco.UI#readme) project. - -## Getting Started with the UI Library - -The [Storybook](https://uui.umbraco.com/) is the starting point for working with the Umbraco UI Library. The Storybook contains two tabs: - -1. Canvas - The Canvas tab allows to use the interactive controls. - -
-2. Docs - Here, you can find code examples for all the stories and use them in your markup. You can look it up by tag name or head to the project repository, where, in the packages folder, you will find all the component packages with all the necessary scripts and examples in the readme files. - -
diff --git a/10/umbraco-cms/fundamentals/backoffice/README.md b/10/umbraco-cms/fundamentals/backoffice/README.md deleted file mode 100644 index 80e8f003ac8..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/README.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -description: >- - In this article you can learn more about the common terms and concepts that - are used throughout the Umbraco Backoffice. ---- - -# Backoffice - -In this article you can learn more about the common terms and concepts that are used throughout the Umbraco backoffice. - -## [Login screen](login.md) - -When you go to the backoffice for the first time, you're presented with the login screen. - -![Login screen](images/backoffice-login.png) - -[Read more about the login screen](login.md). - -## [Section](sections.md) - -A section in Umbraco is where you do specific tasks related to that section. For example Content, Settings and Users. You can navigate between the different sections of the backoffice by clicking the corresponding icon in the section menu. - -
- -_The **Section menu** is the horizontal menu located on the top of the backoffice._ - -[Read more about the section menu](sections.md). - -## [Tree](../../extending/section-trees/) - -A tree is a hierarchical list of items related (and usually restricted) to a specific concept, like for example content or media. - -You can expand trees by clicking the down arrow ![](images/expand-node.png) to the left of the node or by double-clicking the node. - -
- -[Read more about the Tree](../../extending/section-trees/) - -## Node - -A node is an item in a tree. Images and folders in the Media section are shown as nodes in the Media tree, pages and content in the Content tree and so forth. - -## [Dashboards](../../extending/dashboards.md) - -A dashboard is the main view you are presented with when entering a section within the backoffice. It can be used to show valuable information to the users of the system. - -_Default dashboard in the content section_ - -
- -[Read more about Dashboards](../../extending/dashboards.md) - -## Editor - -An editor is what you use to edit different items within the backoffice. There are editors specific to editing stylesheets, there are editors for editing Macros and so forth. - -## [Content](../data/defining-content/) - -Content is what you find in the Content section. Each item in the tree is called a **content node**. Each content node in the content tree consists of different fields, and each of them are defined by a Document Type. - -[Read more about Content](../data/defining-content/) - -## Document Type - -Document Types define the types of content nodes that backoffice users can create in the content tree. Each Document Type contains different properties. Each property has a specific Data Type for example text or number. - -### Properties - -Every Document Type has properties. These are the fields that the content editor is allowed to edit for the content node. - -### [Data Type](../data/data-types/) - -Each Document Type property has a Data Type which defines the type of input of that property. Data Types reference a Property Editor and are configured in the Umbraco backoffice in the Settings section. A Data Type can be something basic (textstring, number, true/false) or more complex (multi-node tree picker, image cropper, etc). - -[Read more about Data Types](../data/data-types/) - -### [Property Editors](property-editors/) - -A property editor is the view used by Data Types to insert content into Umbraco. An example of a property editor is the _Textarea_. It's possible to have many Textarea Data Types with different settings that all use the Textarea property editor. - -[Read more about Property Editors](property-editors/) - -## [Media](../data/creating-media/) - -Media items are used to store assets like images and video within the Media section and can be referenced from your content. - -[Read more about Media](../data/creating-media/) - -### Media Types - -Media Types are similar to Document Types in Umbraco, except they are specifically for media items in the Media section. - -Umbraco comes with 3 default Media Types: **File**, **Folder** and **Image**. - -## [Members](../data/members.md) - -A member is someone who has access to signup, register and login into your **public website** and is not to be confused with Users. - -[Read more about Members](../data/members.md) - -### Member Types - -Similar to a Document Type and a Media Type. You are able to define custom properties to store on a member such as twitter username or website URL. - -## [Templates](../design/templates/) - -A Template is where you define the HTML markup of your website and also where you output the data from your content nodes. - -[Read more about Templates](../design/templates/) - -## Packages - -A package is the Umbraco term for a module or plugin used to extend Umbraco. Packages can be found in the [Packages section of Our Umbraco](https://our.umbraco.com/projects/). - -## [Macros](../../reference/templating/macros/) - -A macro is a reusable piece of functionality that you can reuse throughout your site. Macros can be configured with parameters and used on content nodes that has a Rich Text Editor, a Grid editor or a Macro Picker property. You can define what macros are available for your editors to use. When an editor inserts a macro it will prompt them to fill out any of the defined parameters for the macro. - -[Read more about Macros](../../reference/templating/macros/) - -### [Macro Parameter Editor](../../extending/macro-parameter-editors.md) - -A parameter editor defines the usage of a property editor for use as a parameter for Macros. - -[Read more about the Macro Parameter Editor](../../extending/macro-parameter-editors.md) - -## Users - -A user is someone who has access to the **Umbraco backoffice** and is not to be confused with Members. When Umbraco has been installed a user will automatically be generated with the login (email) and password entered during installation. Users can be created, edited and managed in the User section. - -## [Content Templates](content-templates.md) - -Content Templates provide a blueprint for content nodes based on an existing node. diff --git a/10/umbraco-cms/fundamentals/backoffice/content-templates.md b/10/umbraco-cms/fundamentals/backoffice/content-templates.md deleted file mode 100644 index 096d5842b4d..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/content-templates.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -meta.Title: Content Templates in Umbraco -description: >- - In this article you can learn about how to create and use Content Templates in - Umbraco. ---- - -# Content Templates - -Content Templates allows a content editor to create a blueprint for new content nodes based on an existing node. - -{% embed url="https://youtu.be/tz7dRStOo2Y" %} -Learn how to use the Content Templates in Umbraco -{% endembed %} - -## Create - Method 1 - -{% hint style="warning" %} -Before following this method you should have some [content](../data/defining-content/#3.-creating-the-content) created beforehand. -{% endhint %} - -Select a **Content node** from the **Content** menu: - -![Content Menu](images/v8-01-Content-Menu.png) - -Right-click the Content node and select the **Create Content Template** option. Alternatively, select the **Actions** dropdown of the content node and select the **Create Content Template** option: - -![Actions Button](images/v8-02-Actions-Menu.png) - -Give your content template a **Name**: - -![Content Template Name Field](images/v8-03-Name-Content-Template.png) - -Click the **Create** button and if the creation was successful, you will see a success notification: - -![Create Button](images/v8-04-Save-Content-Template.png) - -The new content template will be created in **Content Templates** node of the **Settings** tree: - -![New Content Template](images/v8-05-Find-Content-Template.png) - -{% hint style="info" %} -Refresh your browser, if you do not see the new content template in the **Content Templates** folder. -{% endhint %} - -## Create - Method 2 - -Click on the **Settings** menu: - -![Settings Menu](images/v8-07-Settings-Menu.png) - -Right-click on the **Content Templates** tree and select the **Create** menu item: - -![Create Content Template](images/v8-08-Create-Content-Template.png) - -Select the Document Type you want to create a content template for: - -![Select Content Type](images/v8-09-Select-Content-Type.png) - -Give your content template a **Name** and click the **Save** button: - -![Content Template Name Field](images/v8-10-Save-Template.png) - -The new content template will be created in **Content Templates** folder of the **Settings** tree: - -![New Content Template](images/v8-11-Find-Template.png) - -## Edit - -To edit an existing content template, select a content template from the **Content Templates** folder of the **Settings** tree. When you have finished editing click the **Save** button: - -![Edit Content Template](images/v8-06-Edit-Content-Template.png) - -## Use - -Once you have created a content template, you can use the template to create new content nodes. To use a content template, right-click the **Content** tree and select **Create**: - -![Create From Template](images/v8-12-Create-From-Template.png) - -When you click on a Document Type that has a content template you will see to options: - -* Create a new node based on a content template -* Create a blank one - -![Select Template](images/v8-13-Select-Template.png) diff --git a/10/umbraco-cms/fundamentals/backoffice/images/01-Content-Menu.png b/10/umbraco-cms/fundamentals/backoffice/images/01-Content-Menu.png deleted file mode 100644 index fd1aa38c909..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/01-Content-Menu.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/02-Actions-Menu.png b/10/umbraco-cms/fundamentals/backoffice/images/02-Actions-Menu.png deleted file mode 100644 index 9a4c63c5b7a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/02-Actions-Menu.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/03-Name-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/03-Name-Content-Template.png deleted file mode 100644 index 30bd53bd31c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/03-Name-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/04-Save-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/04-Save-Content-Template.png deleted file mode 100644 index 92bda986ff2..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/04-Save-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/05-Find-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/05-Find-Content-Template.png deleted file mode 100644 index a27e7fccade..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/05-Find-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/06-Edit-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/06-Edit-Content-Template.png deleted file mode 100644 index 28fc44c2d47..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/06-Edit-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/07-Settings-Menu.png b/10/umbraco-cms/fundamentals/backoffice/images/07-Settings-Menu.png deleted file mode 100644 index b337fcbdd64..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/07-Settings-Menu.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/08-Create-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/08-Create-Content-Template.png deleted file mode 100644 index 1e02b91ac87..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/08-Create-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/09-Select-Content-Type.png b/10/umbraco-cms/fundamentals/backoffice/images/09-Select-Content-Type.png deleted file mode 100644 index 1667a1004e1..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/09-Select-Content-Type.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/10-Save-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/10-Save-Template.png deleted file mode 100644 index 3eacba37b32..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/10-Save-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/11-Find-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/11-Find-Template.png deleted file mode 100644 index ed641e4ff90..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/11-Find-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/12-Create-From-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/12-Create-From-Template.png deleted file mode 100644 index 147b376c44c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/12-Create-From-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/13-Select-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/13-Select-Template.png deleted file mode 100644 index 904351ebe5e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/13-Select-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Assign-Access-Languages.png b/10/umbraco-cms/fundamentals/backoffice/images/Assign-Access-Languages.png deleted file mode 100644 index ef317d03904..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Assign-Access-Languages.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/BlockEditorConfigurationProgramatically.png b/10/umbraco-cms/fundamentals/backoffice/images/BlockEditorConfigurationProgramatically.png deleted file mode 100644 index 949ae88fff5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/BlockEditorConfigurationProgramatically.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/BlockEditorContentCreated.png b/10/umbraco-cms/fundamentals/backoffice/images/BlockEditorContentCreated.png deleted file mode 100644 index 4edfd5aba87..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/BlockEditorContentCreated.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Content.png b/10/umbraco-cms/fundamentals/backoffice/images/Content.png deleted file mode 100644 index 9ab10d1fe04..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Developer.png b/10/umbraco-cms/fundamentals/backoffice/images/Developer.png deleted file mode 100644 index ce155b66cc5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Developer.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/English_get.png b/10/umbraco-cms/fundamentals/backoffice/images/English_get.png deleted file mode 100644 index 70e3950dff0..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/English_get.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Forms.png b/10/umbraco-cms/fundamentals/backoffice/images/Forms.png deleted file mode 100644 index 6dfdf03de1b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Forms.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Help.png b/10/umbraco-cms/fundamentals/backoffice/images/Help.png deleted file mode 100644 index bf96869ef08..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Help.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Infinite-editing.gif b/10/umbraco-cms/fundamentals/backoffice/images/Infinite-editing.gif deleted file mode 100644 index b24121d92ba..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Infinite-editing.gif and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Media.png b/10/umbraco-cms/fundamentals/backoffice/images/Media.png deleted file mode 100644 index 77f0746531b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Media.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Members.png b/10/umbraco-cms/fundamentals/backoffice/images/Members.png deleted file mode 100644 index d805f89a211..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Members.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Settings.png b/10/umbraco-cms/fundamentals/backoffice/images/Settings.png deleted file mode 100644 index 3c4a206e0a2..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Settings.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/Users.png b/10/umbraco-cms/fundamentals/backoffice/images/Users.png deleted file mode 100644 index d589c44c76f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/Users.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/allow-variance.png b/10/umbraco-cms/fundamentals/backoffice/images/allow-variance.png deleted file mode 100644 index 5fed09efd7c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/allow-variance.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/allow-variance_v10.png b/10/umbraco-cms/fundamentals/backoffice/images/allow-variance_v10.png deleted file mode 100644 index 828f73cdceb..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/allow-variance_v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/backoffice-login.png b/10/umbraco-cms/fundamentals/backoffice/images/backoffice-login.png deleted file mode 100644 index 736a44a2f3e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/backoffice-login.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/expand-node.png b/10/umbraco-cms/fundamentals/backoffice/images/expand-node.png deleted file mode 100644 index 419c6ac6582..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/expand-node.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version (1).svg b/10/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version (1).svg deleted file mode 100644 index fd3509507a6..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version (1).svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version.svg b/10/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version.svg deleted file mode 100644 index fd3509507a6..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/highlight-dashboard.png b/10/umbraco-cms/fundamentals/backoffice/images/highlight-dashboard.png deleted file mode 100644 index 48358e348a2..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/highlight-dashboard.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/highlight-sections.png b/10/umbraco-cms/fundamentals/backoffice/images/highlight-sections.png deleted file mode 100644 index b6f4dd6069f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/highlight-sections.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/highlight-tree.png b/10/umbraco-cms/fundamentals/backoffice/images/highlight-tree.png deleted file mode 100644 index ff505054c15..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/highlight-tree.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/invariant-property-locked.png b/10/umbraco-cms/fundamentals/backoffice/images/invariant-property-locked.png deleted file mode 100644 index 7159ba8b58a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/invariant-property-locked.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/is-container (1).svg b/10/umbraco-cms/fundamentals/backoffice/images/is-container (1).svg deleted file mode 100644 index b43024c3d0e..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/is-container (1).svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/is-container.svg b/10/umbraco-cms/fundamentals/backoffice/images/is-container.svg deleted file mode 100644 index b43024c3d0e..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/is-container.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/languages.png b/10/umbraco-cms/fundamentals/backoffice/images/languages.png deleted file mode 100644 index 3820e0cae49..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/languages.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/languages_v10.png b/10/umbraco-cms/fundamentals/backoffice/images/languages_v10.png deleted file mode 100644 index d8e66c08b24..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/languages_v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/locked (1).svg b/10/umbraco-cms/fundamentals/backoffice/images/locked (1).svg deleted file mode 100644 index 782eb1006fb..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/locked (1).svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/locked.svg b/10/umbraco-cms/fundamentals/backoffice/images/locked.svg deleted file mode 100644 index 782eb1006fb..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/locked.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/login-backoffice-login.png b/10/umbraco-cms/fundamentals/backoffice/images/login-backoffice-login.png deleted file mode 100644 index 33a9ca746be..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/login-backoffice-login.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/protected (1).svg b/10/umbraco-cms/fundamentals/backoffice/images/protected (1).svg deleted file mode 100644 index 3aab0c725f5..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/protected (1).svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/protected.svg b/10/umbraco-cms/fundamentals/backoffice/images/protected.svg deleted file mode 100644 index 3aab0c725f5..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/images/protected.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/10/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections (1).png b/10/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections (1).png deleted file mode 100644 index 246bb98a467..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections.png b/10/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections.png deleted file mode 100644 index 246bb98a467..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_dashboard.jpg b/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_dashboard.jpg deleted file mode 100644 index fdac204aafe..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_dashboard.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_login.jpg b/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_login.jpg deleted file mode 100644 index 6627a757b7c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_login.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_sections.jpg b/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_sections.jpg deleted file mode 100644 index b1dc1cd708e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_sections.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_tree.jpg b/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_tree.jpg deleted file mode 100644 index 6de9e5a00d6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_tree.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-01-Content-Menu.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-01-Content-Menu.png deleted file mode 100644 index dd375cca662..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-01-Content-Menu.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-02-Actions-Menu.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-02-Actions-Menu.png deleted file mode 100644 index 4f038a5eb3f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-02-Actions-Menu.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-03-Name-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-03-Name-Content-Template.png deleted file mode 100644 index 6a41f9aa5d6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-03-Name-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-04-Save-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-04-Save-Content-Template.png deleted file mode 100644 index f7a15cb548e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-04-Save-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-05-Find-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-05-Find-Content-Template.png deleted file mode 100644 index 244f5d796b7..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-05-Find-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-06-Edit-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-06-Edit-Content-Template.png deleted file mode 100644 index 5cdb17c7422..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-06-Edit-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-07-Settings-Menu.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-07-Settings-Menu.png deleted file mode 100644 index e1f6910d596..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-07-Settings-Menu.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-08-Create-Content-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-08-Create-Content-Template.png deleted file mode 100644 index 2c610e04b97..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-08-Create-Content-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-09-Select-Content-Type.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-09-Select-Content-Type.png deleted file mode 100644 index ca0480f2704..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-09-Select-Content-Type.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-10-Save-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-10-Save-Template.png deleted file mode 100644 index 1d323d33295..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-10-Save-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-11-Find-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-11-Find-Template.png deleted file mode 100644 index a7cde6aabef..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-11-Find-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-12-Create-From-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-12-Create-From-Template.png deleted file mode 100644 index 3b8be3c5dca..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-12-Create-From-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/v8-13-Select-Template.png b/10/umbraco-cms/fundamentals/backoffice/images/v8-13-Select-Template.png deleted file mode 100644 index 251ae8eded3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/v8-13-Select-Template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/varying-content.png b/10/umbraco-cms/fundamentals/backoffice/images/varying-content.png deleted file mode 100644 index 41247e7065e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/varying-content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/varying-content_v10.png b/10/umbraco-cms/fundamentals/backoffice/images/varying-content_v10.png deleted file mode 100644 index 79efa211c19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/varying-content_v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/varying-properties.png b/10/umbraco-cms/fundamentals/backoffice/images/varying-properties.png deleted file mode 100644 index ff34a501419..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/varying-properties.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/images/varying-properties_v10.png b/10/umbraco-cms/fundamentals/backoffice/images/varying-properties_v10.png deleted file mode 100644 index fd949f8dad9..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/images/varying-properties_v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/infinite-editing.md b/10/umbraco-cms/fundamentals/backoffice/infinite-editing.md deleted file mode 100644 index da0c4a320bb..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/infinite-editing.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -meta.Title: Infinite Editing in Umbraco -description: >- - This section explains how the concept of infinite editing in the Umbraco - backoffice works. ---- - -# Infinite Editing - -This feature enables you to work with your content without losing the context of what you are doing. - -Document Types are in different sections than content but infinite editing enables you to make changes to them directly from the content you are editing. - -![Infinite Editing](images/Infinite-editing.gif) - -In the example showcased above, prevalues are being added to a Data Type, without losing the context of the content that's being worked on. The example also shows how you can edit images, without being sent to the 'Media' section. - -## Customize - -Infinite editing is a feature that comes out of the box with Umbraco. The feature can be customized, which enables you as a developer to improve the workflow for your editors. - -## Read more - -* [Umbraco 8: Infinite Editing (official blog post from Umbraco HQ)](https://umbraco.com/blog/umbraco-8-infinite-editing/) diff --git a/10/umbraco-cms/fundamentals/backoffice/login.md b/10/umbraco-cms/fundamentals/backoffice/login.md deleted file mode 100644 index 2f0c5a90f68..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/login.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -meta.Title: Configure and customize the Login screen -description: >- - In this article you can learn the various ways of customizing the Umbraco - backoffice login screen and form. ---- - -# Login - -To access the backoffice, you will need to login. You can do this by adding `/umbraco` at the end of your website URL, e.g. http://mywebsite.com/umbraco. - -You will be presented with a login form similar to this: - -![Login screen](images/login-backoffice-login.png) - -The **login** screen contains a **Greeting**, **Email**, **Password** field and optionally a **Forgotten password** link - -Below, you will find instructions on how to customise the login screen. - -## Greeting - -The login screen features a greeting which you can personalize by overriding the existing language translation keys. To do this, create a 'user' translation file for the default language of your Umbraco site, (usually en-US) to override the greetings. For en-US, you'd create a file called: `en_us.user.xml` in the directory `~/config/lang/`. Then take the relevant keys (listed below) and add them to your `~/config/lang/en_us.user.xml` file, and update the greetings as necessary. Note: the `config` directory needs to be in the root of your project (_not_ the `wwwroot`). - -```xml - - - - Happy super Sunday - Happy manic Monday - Happy tubular Tuesday - Happy wonderful Wednesday - Happy thunderous Thursday - Happy funky Friday - Happy Caturday - - -``` - -You can customize other text on the login screen as well. First, grab the default values and keys from `~/umbraco/config/lang/en.xml`. Thereafter copy the ones you want to translate into `~/config/lang/en_us.user.xml` file. Note: the new /config/ folder needs to be created at the site root. - -## Password reset - -The **Forgotten password?** link allows your backoffice users to reset their password. To use this feature, you will need to add the following key to the `Umbraco.Cms.Security` section in the `appsettings.json` file: - -```json -"Umbraco": { - "CMS": { - "Security": { - "AllowPasswordReset": true - } - } -} -``` - -Set it to `true` to enable the password reset feature, and `false` to disable the feature. - -You will also need to configure an Simple Mail Transfer Protocol (SMTP) server in your `appsettings.json` file. When you get a successful result on the SMTP configuration when running a health check in the backoffice, you are good to go! - -An example: - -```json -"Umbraco": { - "CMS": { - "Global": { - "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "Smtp": { - "From": "noreply@test.com", - "Host": "127.0.0.1", - "Username": "username", - "Password": "password" - } - } - } -} -``` - -## Custom background image and logo - -It is possible to customize the background image and the logo for the backoffice login screen by adding the `"Content"` section in the `appsettings.json` file: - -```json -"Umbraco": { - "CMS": { - "Content": { - "LoginBackgroundImage": "../myImagesFolder/myLogin.jpg", - "LoginLogoImage": "../myImagesFolder/myLogo.svg" - } - } -} -``` - -The `LoginBackgroundImage` and `LoginLogoImage` are referenced from the `/wwwroot/umbraco/` folder. - -To affect the styling of the images add a folder to the `/App_Plugins` folder containing a `CSS` folder, containing a CSS file, and a package.manifest file. An example structure might be: - -``` -/App_Plugins - /myLoginFolder - /css - /myLoginStyles.css - /package.manifest -``` - -An example stylesheet might be: - -```css - .login-overlay { - background-color: #000; - } - - .login-overlay__background-image { - /* Override background image opacity here if needed */ - /* opacity is set to 0.05 by default if background images is set */ - /*opacity:0.05;*/ - opacity:0; - background-size:contain; - background-image: none; - } - - div.login-overlay__logo { - width: 10%; - } -``` - -An example package.manifest might be: - -```json - { - css: [ - '~/App_Plugins/myLoginFolder/css/myLoginStyles.css' - ] - } -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/logviewer.md b/10/umbraco-cms/fundamentals/backoffice/logviewer.md deleted file mode 100644 index a0bf80cfd89..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/logviewer.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -meta.Title: Log Viewer -keywords: logging logviewer logs serilog messagetemplates logs v8 version8 -description: Information on using the Umbraco log viewer in version 8 ---- - -# Log Viewer - -Umbraco ships with a built-in Log Viewer feature. This allows you to filter and view log entries and perform much more complex search queries. This helps you finding the log entries that you are interested in. You can find the log viewer in the settings section. - -## Benefits - -Have you ever wanted to find all log entries which contains the same request ID? Or find all items in the log where a property called duration is greater than 1000ms? - -With the power of structured logging and a query language we are able to search and find log items for specific scenarios. When debugging the site you should now have more power to see and find patterns in your log files and get rid of those errors. - -## Example queries - -Here are a handful example queries to get you started, however the saved searches contain some further examples. For more details on the syntax head over to the https://github.com/serilog/serilog-filters-expressions project. - -**Find all logs that are from the namespace 'Umbraco.Core'**\ -`StartsWith(SourceContext, 'Umbraco.Core')`\\ - -**Find all logs that have the property 'Duration' and the duration is greater than 1000ms**\ -`Has(Duration) and Duration > 1000`\\ - -**Find all logs where the message has localhost in it with SQL like**\ -`@Message like '%localhost%'`\\ - -## Saved Searches - -Sometimes you want to use a custom query more often. It is possible to save a query and use the dropdown to re-use your saved search. To add a new saved search, use the search box to type your query and click the star icon. In doing so you can give it a friendly name. The saved queries are saved in the database in the table `umbracoLogViewerQuery`. - -## Implementing your own Log Viewer - -With the flexibility of Umbraco, we give you the power to implement your own `ILogViewer`. This makes it possible to fetch logs and the saved searched from a different location such as Azure table storage. - -### Create your own implementation - -To do this we can implement a base class `SerilogLogViewerSourceBase` from `Umbraco.Cms.Core.Logging.Viewer` like so. - -{% hint style="info" %} -This uses the `Azure.Data.Tables` NuGet package. -{% endhint %} - -```csharp -using Azure; -using Azure.Data.Tables; -using Serilog.Events; -using Serilog.Formatting.Compact.Reader; -using Serilog.Sinks.AzureTableStorage; -using Umbraco.Cms.Core.Logging.Viewer; -using ITableEntity = Azure.Data.Tables.ITableEntity; - -namespace My.Website; - -public class AzureTableLogViewer : SerilogLogViewerSourceBase -{ - public AzureTableLogViewer(ILogViewerConfig logViewerConfig, Serilog.ILogger serilogLog, ILogLevelLoader logLevelLoader) - : base(logViewerConfig, logLevelLoader, serilogLog) - { - } - - public override bool CanHandleLargeLogs => true; - - // This method will not be called - as we have indicated that this 'CanHandleLargeLogs' - public override bool CheckCanOpenLogs(LogTimePeriod logTimePeriod) => throw new NotImplementedException(); - - protected override IReadOnlyList GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take) - { - var client = - new TableClient( - "DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=KEY;EndpointSuffix=core.windows.net", - "Logs"); - - // Table storage does not support skip, only take, so the best we can do is to not fetch more entities than we need in total. - // See: https://learn.microsoft.com/en-us/rest/api/storageservices/writing-linq-queries-against-the-table-service#returning-the-top-n-entities for more info. - var requiredEntities = skip + take; - IEnumerable results = client.Query().Take(requiredEntities); - - return results - .Skip(skip) - .Take(take) - .Select(x => LogEventReader.ReadFromString(x.Data)) - // Filter by timestamp to avoid retrieving all logs from the table, preventing memory and performance issues - .Where(evt => evt.Timestamp >= logTimePeriod.StartTime.Date && - evt.Timestamp <= logTimePeriod.EndTime.Date.AddDays(1).AddSeconds(-1)) - .Where(filter.TakeLogEvent) - .ToList(); - } - - public override IReadOnlyList? GetSavedSearches() - { - // Optional: If you want to store saved searches in the Azure Table Storage, implement here a method to fetch from the Azure Table. - return base.GetSavedSearches(); - } - - public override IReadOnlyList? AddSavedSearch(string? name, string? query) - { - //Optional: If you want to store saved searches in the Azure Table Storage, implement here a method to add to the Azure Table. - return base.AddSavedSearch(name, query); - } - - public override IReadOnlyList? DeleteSavedSearch(string? name, string? query) - { - //Optional: If you want to store saved searches in the Azure Table Storage, implement here a method to remove from the Azure Table. - return base.DeleteSavedSearch(name, query); - } -} - -public class AzureTableLogEntity : LogEventEntity, ITableEntity -{ - public DateTimeOffset? Timestamp { get; set; } - - public ETag ETag { get; set; } -} -``` - -Keep in mind that we have to implement our own version of a `LogEventEntity`. This is because the `TableClient` needs whatever it is fetching to implement the `ITableEntity` interface. - -### Register implementation - -Umbraco needs to be made aware that there is a new implementation of an `ILogViewer` to register. We also need to replace the default JSON LogViewer that we ship in the core of Umbraco. - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Infrastructure.DependencyInjection; - -namespace My.Website; - -public class LogViewerSavedSearches : IComposer -{ - public void Compose(IUmbracoBuilder builder) => builder.SetLogViewer(); -} -``` - -### Configure Umbraco to log to Azure Table Storage - -Now with the above two classes, we have the plumbing in place to view logs from an Azure Table. However, we are not persisting our logs into the Azure table storage account. So we need to configure the Serilog logging pipeline to store our logs into Azure table storage. - -* Install Serilog.Sinks.AzureTableStorage from Nuget -* Add a new sink to the appsettings with credentials (so logs persist to Azure) - -The following sink needs to be added to the array [`Serilog:WriteTo`](https://github.com/serilog/serilog-sinks-azuretablestorage#json-configuration). - -```json -{ -"Name": "AzureTableStorage", -"Args": { - "storageTableName": "LogEventEntity", - "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact", - "connectionString": "DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=KEY;EndpointSuffix=core.windows.net"} -} -``` - -For more in depth information about logging and how to configure it, please read the [logging documentation](../code/debugging/logging.md). - -### Compact Log Viewer - Desktop App - -This is a desktop tool for viewing & querying JSON log files from disk in the same way as the built in logviewer dashboard of Umbraco. - -[English badge](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge\&ocid=badge) diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/README.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/README.md deleted file mode 100644 index 42edb59aef5..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/README.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -meta.Title: Property editors -description: >- - A Property editor is the editor that a Data Type references, and it's defined - in a JSON manifest file and an associated JavaScript file. ---- - -# Property Editors - -A Property Editor is the editor that a Data Type references. A Data Type is defined by a user in the Umbraco backoffice and references a Property Editor. In Umbraco a Property Editor is defined in a JSON manifest file and associated JavaScript files. - -When creating a Data Type, specify the property editor for the Data Type to use by selecting from the "Property editor" list (as shown below). - -![Data Type Definition](images/Media-picker-dataType-v9.png) - -## [Built-in Property Editors in Umbraco](built-in-umbraco-property-editors/) - -Umbraco comes pre-installed with many useful property editors. - -## More information - -* [Customizing Data Types](../../data/data-types/) - -## Tutorials - -* [How to create a custom Property Editor](../../../tutorials/creating-a-property-editor/) diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png deleted file mode 100644 index b77fcfc1257..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png deleted file mode 100644 index 644ec9d1b1a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png deleted file mode 100644 index ae25f727ec1..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png deleted file mode 100644 index 27a9a510790..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png deleted file mode 100644 index b519f0b755b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png deleted file mode 100644 index 826d46925e4..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png deleted file mode 100644 index fe5fec9d0df..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png deleted file mode 100644 index 5509be958d5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png deleted file mode 100644 index aee9a56f88a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png deleted file mode 100644 index aeb71eb6354..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg deleted file mode 100644 index 8b20c59740b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg deleted file mode 100644 index 48ca8012ceb..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg deleted file mode 100644 index 265f40b2b50..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg deleted file mode 100644 index d55344cfab6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png deleted file mode 100644 index 55f022f185c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg deleted file mode 100644 index 06e3952f0d6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg deleted file mode 100644 index 0bc57cb6dcb..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Install-Sample-Configuration.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Install-Sample-Configuration.png deleted file mode 100644 index 3c461f50f2a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Install-Sample-Configuration.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Resizing-Blocks.gif b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Resizing-Blocks.gif deleted file mode 100644 index 3cd187ba55c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Resizing-Blocks.gif and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif deleted file mode 100644 index b5a762aad5d..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/resizing-block-block-grid.gif b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/resizing-block-block-grid.gif deleted file mode 100644 index f56d714d12b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/resizing-block-block-grid.gif and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png deleted file mode 100644 index 51a442213de..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v8.png deleted file mode 100644 index 0ea95d1f653..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType.png deleted file mode 100644 index da2e4783a21..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Content.png deleted file mode 100644 index 748994a5133..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-DataType.png deleted file mode 100644 index 4c3e82f6475..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-Content.png deleted file mode 100644 index 9f32f5a1403..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-DataType.png deleted file mode 100644 index ffcdc6226ed..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png deleted file mode 100644 index 9d2fd30a993..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png deleted file mode 100644 index be48cc06e30..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-config.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-config.png deleted file mode 100644 index b1a7bebeeee..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-config.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-configuration.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-configuration.jpg deleted file mode 100644 index 1a1669ea764..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-configuration.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-NO-SIDEBAR-rows.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-NO-SIDEBAR-rows.jpg deleted file mode 100644 index 6f2ee70af01..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-NO-SIDEBAR-rows.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-rows.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-rows.jpg deleted file mode 100644 index 82c269292fa..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-rows.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios-1.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios-1.jpg deleted file mode 100644 index 68e9eaa12b6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios-1.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios.jpg deleted file mode 100644 index 89c46c8e2a6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout.jpg deleted file mode 100644 index c568c3bc883..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/cells.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/cells.png deleted file mode 100644 index 7a08e22f31e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/cells.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/editor.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/editor.png deleted file mode 100644 index f2cabc6bd80..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/editor.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-resizing.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-resizing.png deleted file mode 100644 index 43795bb6e72..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-resizing.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-settings-and-style.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-settings-and-style.png deleted file mode 100644 index be277afce13..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-settings-and-style.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-wireframe.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-wireframe.jpg deleted file mode 100644 index 743294e00e0..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-wireframe.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layout.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layout.png deleted file mode 100644 index 1d56b4e1077..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layout.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layouts.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layouts.png deleted file mode 100644 index 92d35914331..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layouts.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/rows.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/rows.png deleted file mode 100644 index 324ada87d38..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/rows.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/settings.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/settings.png deleted file mode 100644 index 5cbec50a771..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/settings.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Bulk-action.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Bulk-action.png deleted file mode 100644 index 317fcc0be6f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Bulk-action.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png deleted file mode 100644 index 816cd894624..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type-v10.png deleted file mode 100644 index 3f1b3f5769d..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type.png deleted file mode 100644 index b5c12f01a4f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png deleted file mode 100644 index 1bf70361a19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content.png deleted file mode 100644 index afa79301ebb..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v10.png deleted file mode 100644 index 192d2d14d6a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v8.png deleted file mode 100644 index dce3cfb3707..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType.png deleted file mode 100644 index cdb0b000552..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png deleted file mode 100644 index 7a5462d5c5f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v8.png deleted file mode 100644 index e6501f8493b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content.png deleted file mode 100644 index c8f7c80d8db..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-8_1.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-8_1.png deleted file mode 100644 index 19ee214659f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-v8.png deleted file mode 100644 index b3fc75721fc..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType.png deleted file mode 100644 index 9961538e7b7..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-Content.png deleted file mode 100644 index 305193e35a5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType-v10.png deleted file mode 100644 index 7785bfc843a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType.png deleted file mode 100644 index 0488e5ca139..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-app-icon.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-app-icon.png deleted file mode 100644 index e24f72dc290..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-app-icon.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Csv-example-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Csv-example-v8.png deleted file mode 100644 index ad132be4a7f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Csv-example-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png deleted file mode 100644 index 1ebdd54aaaa..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Content.png deleted file mode 100644 index 2460047b337..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Data-Type.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Data-Type.png deleted file mode 100644 index 1b1573f3cdc..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Data-Type.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png deleted file mode 100644 index c0c5dfb8d60..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png deleted file mode 100644 index 71b57446e23..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-Content.png deleted file mode 100644 index 4d69318f166..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v8.png deleted file mode 100644 index 8a23ef3e7dd..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v88.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v88.png deleted file mode 100644 index fe097a4cfab..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v88.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png deleted file mode 100644 index d404b98533b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png deleted file mode 100644 index c8d568092ed..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png deleted file mode 100644 index 83a6fc3ac28..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Json-example-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Json-example-v8.png deleted file mode 100644 index 509f6bc80d8..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Json-example-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png deleted file mode 100644 index 8542a32ceb9..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Setup-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Setup-v8.png deleted file mode 100644 index c3c57f0a063..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Setup-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png deleted file mode 100644 index e71cbb2825f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-definition-example-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-definition-example-v10.png deleted file mode 100644 index d697795c88a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-definition-example-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content-v8.png deleted file mode 100644 index 22adeb1cfed..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content.jpg deleted file mode 100644 index ab98dd1c544..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-8_1.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-8_1.png deleted file mode 100644 index 06b96e1f7aa..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v10.png deleted file mode 100644 index 761f85d1b08..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v8.png deleted file mode 100644 index 47a81f806f8..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType.jpg deleted file mode 100644 index 9ac41a5e833..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-Content.png deleted file mode 100644 index d608e07bddc..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-DataType.png deleted file mode 100644 index aebba80af59..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg deleted file mode 100644 index 4cf7c146c4a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-DataType.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-DataType.jpg deleted file mode 100644 index 5bd2ba0f4fa..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-DataType.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/MediaPicker-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/MediaPicker-DataType-v10.png deleted file mode 100644 index a779088cce0..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/MediaPicker-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png deleted file mode 100644 index 33109a95d23..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png deleted file mode 100644 index 5f01d0e0fac..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content.png deleted file mode 100644 index 7b192ab851c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType-v8.png deleted file mode 100644 index e1b845db8e7..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType.png deleted file mode 100644 index b62615b15de..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content-v8.png deleted file mode 100644 index 83e70feba90..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content.jpg deleted file mode 100644 index 1f59bd1aa4e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-8_1.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-8_1.png deleted file mode 100644 index a5b012f17c6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-v8.png deleted file mode 100644 index 373a1683542..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType.png deleted file mode 100644 index 824437a853c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-Content.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-Content.jpg deleted file mode 100644 index bb3ab928c11..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-Content.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-DataType.png deleted file mode 100644 index f6ce9d537f1..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (1).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (1).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (2).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (2).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (2).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (2).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (3).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (3).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (1).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (1).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (2).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (2).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (3).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (3).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (2).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (2).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content.png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png deleted file mode 100644 index ce2969ab86c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-8_1.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-8_1.png deleted file mode 100644 index 3e2453ac34e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png deleted file mode 100644 index 062da5499b4..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v8.png deleted file mode 100644 index 4f9616254e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_AddContent.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_AddContent.png deleted file mode 100644 index 98414978dc3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_AddContent.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataType-v8.png deleted file mode 100644 index 161b7936661..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataTypeDefinition.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataTypeDefinition.png deleted file mode 100644 index dda7d36f1eb..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataTypeDefinition.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem-v8.png deleted file mode 100644 index 94c5c38a18e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem.png deleted file mode 100644 index da6b1155c87..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem-v8.png deleted file mode 100644 index f762ddad70b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem.png deleted file mode 100644 index fcde18e4093..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NotSupported.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NotSupported.png deleted file mode 100644 index 0c6117c24cd..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NotSupported.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema-v8.png deleted file mode 100644 index d1ce4c68a49..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema.png deleted file mode 100644 index 08e3d50241a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode-v8.png deleted file mode 100644 index 7ca1a2aa5cd..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode.png deleted file mode 100644 index f0339bd55c7..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v7.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v7.png deleted file mode 100644 index 1b127cb708f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v7.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png deleted file mode 100644 index dffc9993677..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v10.png deleted file mode 100644 index 2127a4f1ced..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v7.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v7.png deleted file mode 100644 index 142fa243b8b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v7.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v8.png deleted file mode 100644 index 8ba95eb0960..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-Content.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-Content.jpg deleted file mode 100644 index 69a93e1b650..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-Content.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-DataType.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-DataType.jpg deleted file mode 100644 index ed7f4b3cd0f..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-DataType.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-Content.png deleted file mode 100644 index 2a794696fc7..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-DataType.png deleted file mode 100644 index 7dff6a53a7a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content (1).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content (1).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content (2).png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content (2).png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content.png deleted file mode 100644 index 7c3e61eae19..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png deleted file mode 100644 index 9712de40e4b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType.png deleted file mode 100644 index 4111a53f682..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-With-Range.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-With-Range.png deleted file mode 100644 index 94a6744a65d..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-With-Range.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-no-range.PNG b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-no-range.PNG deleted file mode 100644 index defbec9d5c0..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-no-range.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Data-Type-Definition-Example.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Data-Type-Definition-Example.png deleted file mode 100644 index 83075cd06e3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Data-Type-Definition-Example.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v10.png deleted file mode 100644 index 28df576cc66..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v8.png deleted file mode 100644 index 4cdceafb098..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png deleted file mode 100644 index 11b0429ae07..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png deleted file mode 100644 index a705fe2e373..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-Limit-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-Limit-v8.png deleted file mode 100644 index 10056565a9e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-Limit-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v10.png deleted file mode 100644 index c9fc0f6ab18..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v8.png deleted file mode 100644 index 57e204be5da..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png deleted file mode 100644 index 3fac1920ccf..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png deleted file mode 100644 index 0d11476b79d..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v10.png deleted file mode 100644 index 63c007e993b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v8.png deleted file mode 100644 index 6be488e2c47..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-Content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-Content.png deleted file mode 100644 index f9e2ee1d4f9..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-Content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-DataType-742.jpg b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-DataType-742.jpg deleted file mode 100644 index 3fed90221c1..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-DataType-742.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Typeahead-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Typeahead-v8.png deleted file mode 100644 index 36c7d8ab560..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Typeahead-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png deleted file mode 100644 index b10862a78f2..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-DataType-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-DataType-v8.png deleted file mode 100644 index e2e6107c9e6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-DataType-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png deleted file mode 100644 index 091b76744a6..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup-v8.png deleted file mode 100644 index 31e261468bb..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup.png deleted file mode 100644 index cbc8b32dab8..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/configuration.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/configuration.png deleted file mode 100644 index 7fed23ebeaf..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/configuration.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png deleted file mode 100644 index c52090520a5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png deleted file mode 100644 index 43de1d23057..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/crop.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/crop.png deleted file mode 100644 index 9eab72c6175..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/crop.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/datatype.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/datatype.png deleted file mode 100644 index 679cf442191..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/datatype.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-picker-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-picker-v8.png deleted file mode 100644 index af4255a5566..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-picker-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-time-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-time-v8.png deleted file mode 100644 index 04e52f6da2c..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-time-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example-v10.png deleted file mode 100644 index 64f63e9d0d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example.png deleted file mode 100644 index 16ad8acfcd0..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/emailaddress-datatype-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/emailaddress-datatype-v10.png deleted file mode 100644 index d89366ff495..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/emailaddress-datatype-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/enable-listview.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/enable-listview.png deleted file mode 100644 index 1bd0f06ee35..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/enable-listview.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/focalpoint.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/focalpoint.png deleted file mode 100644 index e315b62e092..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/focalpoint.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-crop-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-crop-v8.png deleted file mode 100644 index fbbb3983ca0..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-crop-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-focalpoint-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-focalpoint-v8.png deleted file mode 100644 index 6d7faf59490..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-focalpoint-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png deleted file mode 100644 index 94e5f4e3056..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v8.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v8.png deleted file mode 100644 index 71285c8067a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v9.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v9.png deleted file mode 100644 index 18bddd8e816..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v9.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png deleted file mode 100644 index e9ed8be01f5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-member-picked.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-member-picked.png deleted file mode 100644 index 303197e4571..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-member-picked.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings1-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings1-v10.png deleted file mode 100644 index 779fee60cd3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings1-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings2-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings2-v10.png deleted file mode 100644 index ddb8b025c09..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings2-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email-settings.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email-settings.png deleted file mode 100644 index 4224ff7dcad..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email-settings.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email.png deleted file mode 100644 index b20a1a15a63..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property-dropdown.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property-dropdown.png deleted file mode 100644 index 55783a6a881..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property-dropdown.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property.png deleted file mode 100644 index 6d8cc9b007a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings-2.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings-2.png deleted file mode 100644 index 3f79b7b6af9..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings-2.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings.png deleted file mode 100644 index c34dd7dd17b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview.png deleted file mode 100644 index 6e6495012ec..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/mandatory-checkbox.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/mandatory-checkbox.png deleted file mode 100644 index 72956366eb8..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/mandatory-checkbox.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker-settings.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker-settings.png deleted file mode 100644 index 888e6eeb6ee..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker-settings.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker.png deleted file mode 100644 index a750e3f6ab5..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png deleted file mode 100644 index 165126a8334..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype-v10.png deleted file mode 100644 index 80cab7f01f1..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype.png deleted file mode 100644 index cca349097c3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others-result.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others-result.png deleted file mode 100644 index d9ca0303dc3..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others-result.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others.png deleted file mode 100644 index 29780fc0632..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/picked-member.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/picked-member.png deleted file mode 100644 index e7ebbae510e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/picked-member.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/upload.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/upload.png deleted file mode 100644 index 2d0bddbf0c7..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/upload.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/wip.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/wip.png deleted file mode 100644 index 0665c1c1b87..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/wip.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-Formats.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-Formats.png deleted file mode 100644 index a2b8de806fe..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-Formats.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-choose-stylesheet.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-choose-stylesheet.png deleted file mode 100644 index 8452a57a36b..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-choose-stylesheet.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-code-tab.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-code-tab.png deleted file mode 100644 index 767739a3f31..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-code-tab.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-content.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-content.png deleted file mode 100644 index 4bf851df863..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-create-style.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-create-style.png deleted file mode 100644 index 5d5ca865fdd..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-create-style.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-datatype-v10.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-datatype-v10.png deleted file mode 100644 index a69a02a082d..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-datatype-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-datatype.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-datatype.png deleted file mode 100644 index 0c22f13a5bf..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-datatype.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-classic-new.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-classic-new.png deleted file mode 100644 index ade47ad435a..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-classic-new.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-classic.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-classic.png deleted file mode 100644 index f03049588fe..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-classic.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-distractionfree.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-distractionfree.png deleted file mode 100644 index 8574056c65e..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/rte-mode-distractionfree.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/toolbar-all-options.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/toolbar-all-options.png deleted file mode 100644 index 7c289bd39bd..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/toolbar-all-options.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/toolbar-full.png b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/toolbar-full.png deleted file mode 100644 index eb6a36ebf34..00000000000 Binary files a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor/images/toolbar-full.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md deleted file mode 100644 index 59ba7b8ffe7..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Built-in Property Editors - diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md deleted file mode 100644 index ec29b4eebc9..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Block Editors - -The Block Editors are property editors that enables you to build advanced editor tools using a set of predefined Document Types. - -Umbraco 10 initially shipped with one Block Editor which is Block List. Block Grid editor has been introduced from version 10.4.0. - -## [Block List](block-list-editor.md) - -## [Block Grid](block-grid-editor.md) diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md deleted file mode 100644 index 5a3f18c2fb9..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md +++ /dev/null @@ -1,743 +0,0 @@ -# Block Grid - -`Alias: Umbraco.BlockGrid` - -`Returns: BlockGridModel` - -The **Block Grid** property editor enables editors to layout their content in the Umbraco backoffice. The content is made of Blocks that can contain different types of data. - -## Sample configuration - -When testing out the property editor, you can use a set of predefined Blocks. The option will only be possible when there are no other Data Types using the Block Grid property editor. - -
- -* Create a new **Data Type**. -* Select the **Block Grid** as the **Property editor**. -* **Install** the "Sample Configuration". - -4 Blocks will be added to the property, ready for testing. - -## Configuring the Block Grid - -The Block Grid property editor is configured via the **Data Types** backoffice interface. - -To set up the Block Grid property editor, follow these steps: - -1. Navigate to the **Settings** section in the Umbraco backoffice. -2. Right-click the **Data Types** folder. -3. Select **Create** -> **New Data Type**. -4. Select **Block Grid** from the list of available property editors. - -You will see the configuration options for a Block Grid property editor as shown below: - -![Block Grid - Data Type Configuration](../../built-in-property-editors/block-editor/images/BlockGridEditor\_Configuration.png) - -The Data Type editor allows you to configure the following properties: - -* **Blocks** - Defines the Block Types available for use in the property. For more information, see [Setup Block Types](block-grid-editor.md#setup-block-types). -* **Amount** - Sets the minimum and/or the maximum number of Blocks that should be allowed at the root of the layout. -* **Live editing mode** - Enabling this option will allow you to see the changes as you are editing them. -* **Editor width** - Overwrites the width of the property editor. This field takes any valid CSS value for "max-width". For example: 100% or 800px. -* **Grid Columns** - Define the number of columns in your grid layout. The default is 12 columns. -* **Layout Stylesheet** - Replaces the built-in Layout Stylesheet. Additionally, you can retrieve the default layout stylesheet to use as a base for your own inspiration or for writing your own stylesheet. -* **Create Button Label** - Overwrites the label on the Create button. - -## Setup Block Types - -Block Types are based on [**Element Types**](../../../../data/defining-content/#what-is-an-element-type). These can be created beforehand or while setting up your Block Types. - -Once you have added an Element Type as a Block Type on your Block Grid Data Type you have the option to configure it. - -![Block Grid - Data Type Block Configuration](../../built-in-property-editors/block-editor/images/BlockGridEditor\_DataType\_Blocks.png) - -[Examples and more details about configuring the Label property](label-property-configuration.md) - -### Groups - -Blocks can also be grouped. This is visible in the Block Catalogue and can also be used to allow a group of Blocks in an Area. - -## Block Configuration Settings - -Each Block has a set of properties that are optional to configure. These are described below. - -### General - -Customize the user experience for your content editors when they work with the Blocks in the Content section. - -* **Label** - Defines a label for the appearance of the Block in the editor. The label can use AngularJS template-string-syntax to display values of properties. - -{% hint style="info" %} -Label example: "My Block \{{myPropertyAlias\}}" will be shown as: "My Block FooBar". - -You can also use more advanced expression using AngularJS filters, like `{{myPropertyAlias | limitTo:100}}` or for a property using Richtext editor `{{myPropertyAlias | ncRichText | truncate:true:100}}`. It is also possible to use properties from the Settings model by using `{{$settings.propertyAlias}}`. - -Get more tips on how to use AngularJS filters in Umbraco CMS from this community-made [Umbraco AngularJS filter cheat sheet](https://joe.gl/ombek/blog/umbraco-angularjs-filter-cheat-sheet/). -{% endhint %} - -* **Content model** - Presents the Element Type used as model for the Content section of this Block. This cannot be changed but you can open the Element Type to perform edits or view the properties available. Useful when writing your Label. -* **Settings model** - Adds a Settings section to your Block based on a given Element Type. When selected you can open the Element Type or choose to remove the Settings section again. - -### Size options - -Customize the Blocks size in the Grid. If you define multiple options, the Block becomes scalable. - -By default, a Block takes up the available width. - -A Block can be resized in two ways: - -1. When a Block is placed in an Area, it will fit to the Areas width. Learn more about [Areas](block-grid-editor.md#areas). -2. A Block can have one or more Column Span options defined. - -A Column Span option is used to define the width of a Block. With multiple Column Span options defined, the Content Editor can scale the Block to fit specific needs. - -Additionally, Blocks can be configured to span rows, this enables one Block to be placed next to a few rows containing other Blocks. - -* **Available column spans** - Defines one or more columns, the Block spans across. For example: in a 12 columns grid, 6 columns is equivalent to half width. By enabling 6 columns and 12 columns, the Block can be scaled to either half width or full width. -* **Available row spans** - Defines the amount of rows the Block spans across. - -See the [scaling blocks](block-grid-editor.md#scaling-blocks) section of this article for an example of how scaling works. - -### Catalogue appearance - -These properties refer to how the Block is presented in the Block catalogue when editors choose which Blocks to use for their content. - -* **Background color** - Defines a background color to be displayed beneath the icon or thumbnail. Example: `#424242`. -* **Icon color** - Changes the color of the Element Type icon. Example: `#242424`. -* **Thumbnail** - Pick an image or Scalable Vector Graphics (SVG) file to replace the icon of the Block in the catalogue. - -The thumbnails for the catalogue are presented in the format of 16:10. We recommend a resolution of 400px width and 250px height. - -### Permissions - -* **Allow in root** - Determines whether the Block can be created at the root of your layout. Turn this off if you only want a Block to appear within Block Areas. -* **Allow in areas** - Determines whether the Block can be created inside Areas of other Blocks. If this is turned off it can still be allowed in Block Areas by defining specific allowed Blocks. - -## Areas - -Blocks can nest other Blocks to support specific compositions. These compositions can be used as a layout for other Blocks. - -To achieve nesting, a Block must have one or more Areas defined. Each Area can contain one or more Blocks. - -Each Area has a size, defined by column and rows spans. The grid for the Areas are based on the same amount of columns as your root grid, unless you choose to change it. - -To scale an Area, click and drag the scale-button in the bottom-right corner of an Area. - -* **Grid Columns for Areas** - Overwrites the amount of columns used for the Area grid. -* **Areas** - Determines whether the Block can be created inside Areas of other Blocks. - -![Block Grid - Areas](../../built-in-property-editors/block-editor/images/BlockGridEditor\_Areas.png) - -### Area configuration - -![Block Grid - Area Configuration](../../built-in-property-editors/block-editor/images/BlockGridEditor\_AreasConfiguration.png) - -* **Alias** - The alias is used to identify this Area. It is being printed by `GetBlockGridHTML()` and used as name for the Area slot in Custom Views. The alias is also available for CSS Selectors to target the HTML-Element representing an Area. -* **Create Button Label** - Overwrites the Create Button Label of the Area. -* **Number of blocks** - Determines the total number of Blocks in an Area. -* **Allowed block types** - When this is empty, all Blocks with Permissions for creation in Areas, will be available. This can be overwritten by specifying the allowed Blocks. Define the types of Blocks or Groups of Blocks that are allowed. Additionally, you can also set how many Blocks of each type/group should be present. - -When allowing a Group of Blocks, you might want to require a specific amount for a certain Block of that Group. This can be done by adding that Block Type to the list as well and set the requirements. - -## Advanced - -These properties are relevant when working with custom views or complex projects. - -* **Custom view** - Overwrites the AngularJS view for the block presentation in the Content editor. Use this view to make a more visual presentation of the Block or make your own editing experience by adding your own AngularJS controller to the view. - -{% hint style="info" %} -Notice that any styling of a Block is scoped. This means that the default backoffice styles are not present for the view of this Block. -{% endhint %} - -* **Custom stylesheet** - Pick your own stylesheet to be used by the Block in the Content editor. -* **Overlay editor size** - Sets the size for the Content editor overlay for editing this block. -* **Hide content editor** - Hides the UI for editing the content in a Block Editor. This is only relevant if you made a custom view that provides the UI for editing of content. - -## Editing Blocks - -When viewing a **Block Grid** property editor in the **Content** section for the first time, you will be presented with the option to **Add content**. - -![Block Grid - Add Content](../../built-in-property-editors/block-editor/images/BlockGridEditor\_AddContent.png) - -Clicking the **Add content** button opens up the **Block Catalogue**. - -![Block Grid - Setup](../../built-in-property-editors/block-editor/images/BlockGridEditor\_BlockPicker.png) - -The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance. - -![Block Grid - example setup](../../built-in-property-editors/block-editor/images/BlockGridEditor\_BlockPicker\_exsetup.png) - -Click the Block Type you wish to create and a new Block will appear in the layout. - -More Blocks can be added to the layout by clicking the Add content button. Alternatively, use the Add content button that appears on hover to add new Blocks between, besides, or above the existing Blocks. - -![Block Grid - Add Content Inline](../../built-in-property-editors/block-editor/images/BlockGridEditor\_AddContentInline.png) - -To delete a Block, click the trash icon which appears on the mouse hover. - -![Block Grid - Delete Content](../../built-in-property-editors/block-editor/images/BlockGridEditor\_DeleteContent.png) - -## Sorting Blocks - -Blocks can be rearranged using the click and drag feature. Move them up or down to place them in the desired order. - -Moving a Block from one Area to another is done in the same way. If a Block is not allowed in the given position, the area will display a red color and not allow the new position. - -![Block Grid - Sorting Blocks](../../built-in-property-editors/block-editor/images/Sorting\_BlockGrid\_Blocks.gif) - -## Scaling Blocks - -If a Block has multiple size options it can be scaled via the UI. This appears in the bottom left corner of the Block. - -The Block is resized using a click-and-drag feature. Moving the mouse will change the size to the size options closest to the mouse pointer. - -

Scale blocks in the grid by dragging from the bottom-right corner.

- -## Rendering Block Grid Content - -Rendering the stored value of your **Block Grid** property editor can be done in two ways: - -1. [Default rendering](block-grid-editor.md#1-default-rendering) -2. [Build your own rendering](block-grid-editor.md#2-build-your-own-rendering) - -### 1. Default rendering - -You can choose to use the built-in rendering mechanism for rendering Blocks using a Partial View for each block. - -The default rendering method is named `GetBlockGridHtmlAsync()` and comes with a few options - for example: - -```csharp -@await Html.GetBlockGridHtmlAsync(Model, "myGrid") -``` - -In the sample above `"myGrid"` is the alias of the Block Grid editor. - -If you are using ModelsBuilder, the example will look like this: - -```csharp -@await Html.GetBlockGridHtmlAsync(Model.MyGrid) -``` - -To use the `GetBlockGridHtmlAsync()` method, you will need to create a Partial View for each Block Type. The Partial View must be named using the alias of the Element Type that is being used as Content Model for the Block Type. - -These Partial View files need to go into the `Views/Partials/blockgrid/Components/` folder. - -Example: `Views/Partials/blockgrid/Components/MyElementTypeAliasOfContent.cshtml`. - -The Partial Views will receive a model of type `Umbraco.Core.Models.Blocks.BlockGridItem`. This model contains `Content` and `Settings` from your block, as well as the configured `RowSpan`, `ColumnSpan`, `ForceLeft`, `ForceRight`, and `Areas` of the Block. - -#### Rendering the Block Areas - -The Partial View for the Block is responsible for rendering its own Block Areas. This is done using another built-in rendering mechanism: - -```csharp -@await Html.GetBlockGridItemAreasHtmlAsync(Model) -``` - -Here you will need to create a Partial View for each Block Type within the Block Area. For the name, use the alias of the Element Type that is being used as Content Model for the Block Type. - -These Partial Views must be placed in the same folder as before, (`Views/Partials/blockgrid/Components/`), and will receive a model of type `Umbraco.Core.Models.Blocks.BlockGridItem`. - -#### Putting it all together - -The following is an example of a Partial View for a Block Type of type `MyElementTypeAliasOfContent`. - -{% code title="MyElementTypeAliasOfContent.cshtml" %} -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; - -@* Render the value of field with alias 'heading' from the Element Type selected as Content section *@ -

@Model.Content.Value("heading")

- -@* Render the block areas *@ -@await Html.GetBlockGridItemAreasHtmlAsync(Model) -``` -{% endcode %} - -If you are using ModelsBuilder, you can make the property rendering strongly typed by letting your view accept a model of type `BlockGridItem`. For example: - -{% code title="MyElementTypeAliasOfContent.cshtml" %} -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage>; -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; - -@* Render the Heading property from the Element Type selected as Content section *@ -

@Model.Content.Heading

- -@* Render the block areas *@ -@await Html.GetBlockGridItemAreasHtmlAsync(Model) -``` -{% endcode %} - -#### Stylesheet - -Using the default rendering together with your layout stylesheet will provide what you need for rendering the layout. - -If you like to use the Default Layout Stylesheet, you must copy the stylesheet to your frontend. You can download the default layout stylesheet from the link within the DataType, we recommend putting the file in the CSS folder, example: `wwwroot/css/umbraco-blockgridlayout.css`. - -```csharp - -``` - -{% hint style="info" %} -A set of built-in Partial Views are responsible for rendering the Blocks and Areas in a grid layout. If you want to tweak or change the way the grid layout is rendered, you can use the built-in Partial Views as a template: - -1. Clone the views from `GitHub`. They can be found in `/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/` -2. Copy the cloned views to the local folder `Views/Partials/blockgrid/` -3. Make changes to your copied views. The entry point for `GetBlockGridHtmlAsync()` is the view `default.cshtml` -{% endhint %} - -### 2. Build your own rendering - -The built-in value converter for the Block Grid property editor lets you use the block data as you like. Call the `Value` method with a type of `BlockGridModel` to have the stored value returned as a `BlockGridModel` instance. - -`BlockGridModel` contains the Block Grid configuration (like the number of columns as `GridColumns`) whilst also being an implementation of `IEnumerable` (see details for `BlockGridItem` above). - -The following example mimics the built-in rendering mechanism for rendering Blocks using Partial Views: - -{% code title="View.cshtml" %} -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using Umbraco.Cms.Core.Models.Blocks -@{ - var grid = Model.Value("myGrid"); - - // get the number of columns defined for the grid - var gridColumns = grid.GridColumns; - - // iterate the block items - foreach (var item in grid) - { - var content = item.Content; - - @await Html.PartialAsync("PathToMyFolderOfPartialViews/" + content.ContentType.Alias, item); - } -} -``` -{% endcode %} - -If you do not want to use Partial Views, you can access the block item data directly within your rendering: - -{% code title="View.cshtml" %} -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using Umbraco.Cms.Core.Models.Blocks -@{ - var grid = Model.Value("myGrid"); - - // get the number of columns defined for the grid - var gridColumns = grid.GridColumns; - - // iterate the block items - foreach (var item in grid) - { - // get the content and settings of the block - var content = item.Content; - var settings = item.Settings; - // get the areas of the block - var areas = item.Areas; - // get the dimensions of the block - var rowSpan = item.RowSpan; - var columnSpan = item.ColumnSpan; - // get forced placement of the block - var forceLeft = item.ForceLeft; - var forceRight = item.ForceRight; - - // render the block data -
-

@(content.Value("title"))

- This block is supposed to span @rowSpan rows and @columnSpan columns -
- } -} -``` -{% endcode %} - -## Write a Custom Layout Stylesheet - -The default layout stylesheet is using CSS Grid. This can be modified to fit your implementation and your project. - -### Adjusting the Default Layout Stylesheet - -To make additions or overwrite parts of the default layout stylesheet, import the default stylesheet at the top of your own file. - -```css -@import 'css/umbblockgridlayout.css'; -``` - -You need to copy the Default Layout Stylesheet to your frontend. You can download the default layout stylesheet from the link within the DataType, we recommend putting the file in the CSS folder, example: `wwwroot/css/umbraco-blockgridlayout.css`. - -### Write a new Layout Stylesheet - -In this case, you would have to write the layout from scratch. - -You are free to pick any style, meaning there is no requirement to use CSS Grid. It is, however, recommended to use CSS Grid to ensure complete compatibility with the Umbraco backoffice. - -### CSS Class structure and available data - -When extending or writing your own layout, you need to know the structure and what data is available. - -For example: You can use the below HTML structure: - -```html -
- - -
- - -
- - - - -
- - -
- - -
- - -
- - -
- - -
- -
-``` - -## Build a Custom Backoffice View - -Building Custom Views for Block representations in Backoffice is based on the same API for all Block Editors. - -[Read about building a Custom View for Blocks here](build-custom-view-for-blocks.md) - -## Creating a Block Grid programmatically - -In this example, we will be creating content programmatically for a "spot" Blocks in a Block Grid. -1. On a document type add a property called **blockGrid**. -2. Then add as editor **Block Grid**. -3. In the Block Grid add a new block and click to **Create new Element Type** -4. Name this element type **spotElement** with the following properties: -- a property called **title** with the editor of **Textstring** -- a property called **text** with the editor of **Textstring** -5. Then on the **Settings model** click to add a new Setting. -6. Then click to **Create new Element Type**. -7. Name this element type **spotSettings** with the following properties: -- a property called **featured** with the editor of **True/false**. - -![Block Grid - Block Configuration](../../../images/BlockEditorConfigurationProgramatically.png) - -The raw input data for the spots looks like this: - -```csharp -new[] -{ - new { Title = "Item one", Text = "This is item one", Featured = false, ColumnSpan = 12, RowSpan = 1, ForceLeft = false, ForceRight = false }, - new { Title = "Item two", Text = "This is item two", Featured = true, ColumnSpan = 6, RowSpan = 2, ForceLeft = false, ForceRight = false } -} -``` - -The resulting JSON object stored for the Block Grid will look like this: - -```json -{ - "layout": { - "Umbraco.BlockGrid": [{ - "contentUdi": "umb://element/bb23fe28160941efa506da7aa314172d", - "settingsUdi": "umb://element/9b832ee528464456a8e9a658b47a9801", - "areas": [], - "columnSpan": 12, - "rowSpan": 1, - "forceLeft": false, - "forceRight": false - }, { - "contentUdi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", - "settingsUdi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", - "areas": [], - "columnSpan": 6, - "rowSpan": 2, - "forceLeft": false, - "forceRight": false - } - ] - }, - "contentData": [{ - "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", - "udi": "umb://element/bb23fe28160941efa506da7aa314172d", - "title": "Item one", - "text": "This is item one" - }, { - "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", - "udi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", - "title": "Item two", - "text": "This is item two" - } - ], - "settingsData": [{ - "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", - "udi": "umb://element/9b832ee528464456a8e9a658b47a9801", - "featured": "0" - }, { - "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", - "udi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", - "featured": "1" - } - ] -} -``` - -For each item in the raw data, we need to create: - -* One `contentData` entry with the _title_ and _text_. -* One `settingsData` entry with the _featured_ value (the checkbox expects `"0"` or `"1"` as data value). -* One `layout` entry with the desired column and row spans. - -All `contentData` and `layoutData` entries need their own unique `Udi` as well as the ID (key) of their corresponding Element Types. In this sample, we only have one Element Type for content (`spotElementType`) and one for settings (`spotSettingsType`). In a real life scenario, there could be any number of Element Type combinations. - -8. First and foremost, we need models to transform the raw data into Block Grid compatible JSON. Create a class called **Model.cs** containing the following: - -{% code title="Models.cs" lineNumbers="true" %} -```csharp -using Newtonsoft.Json; -using Umbraco.Cms.Core; - -namespace My.Site.Models; - -// this is the "root" of the block grid data -public class BlockGridData -{ - public BlockGridData(BlockGridLayout layout, BlockGridElementData[] contentData, BlockGridElementData[] settingsData) - { - Layout = layout; - ContentData = contentData; - SettingsData = settingsData; - } - - [JsonProperty("layout")] - public BlockGridLayout Layout { get; } - - [JsonProperty("contentData")] - public BlockGridElementData[] ContentData { get; } - - [JsonProperty("settingsData")] - public BlockGridElementData[] SettingsData { get; } -} - -// this is a wrapper for the block grid layout, purely required for correct serialization -public class BlockGridLayout -{ - public BlockGridLayout(BlockGridLayoutItem[] layoutItems) => LayoutItems = layoutItems; - - [JsonProperty("Umbraco.BlockGrid")] - public BlockGridLayoutItem[] LayoutItems { get; } -} - -// this represents an item in the block grid layout collection -public class BlockGridLayoutItem -{ - public BlockGridLayoutItem(Udi contentUdi, Udi settingsUdi, int columnSpan, int rowSpan, bool forceLeft, bool forceRight) - { - ContentUdi = contentUdi; - SettingsUdi = settingsUdi; - ColumnSpan = columnSpan; - RowSpan = rowSpan; - ForceLeft = forceLeft; - ForceRight = forceRight; - } - - [JsonProperty("contentUdi")] - public Udi ContentUdi { get; } - - [JsonProperty("settingsUdi")] - public Udi SettingsUdi { get; } - - [JsonProperty("areas")] - // areas are omitted from this sample for abbreviation - public object[] Areas { get; } = { }; - - [JsonProperty("columnSpan")] - public int ColumnSpan { get; } - - [JsonProperty("rowSpan")] - public int RowSpan { get; } - - [JsonProperty("forceLeft")] - public bool ForceLeft { get; } - - [JsonProperty("forceRight")] - public bool ForceRight { get; } - -} - -// this represents an item in the block grid content or settings data collection -public class BlockGridElementData -{ - public BlockGridElementData(Guid contentTypeKey, Udi udi, Dictionary data) - { - ContentTypeKey = contentTypeKey; - Udi = udi; - Data = data; - } - - [JsonProperty("contentTypeKey")] - public Guid ContentTypeKey { get; } - - [JsonProperty("udi")] - public Udi Udi { get; } - - [JsonExtensionData] - public Dictionary Data { get; } -} -``` -{% endcode %} - -9. By injecting [ContentService](../../../../../reference/management/services/contentservice/) and [ContentTypeService](../../../../../reference/management/services/contenttypeservice/) into an API controller, we can transform the raw data into Block Grid JSON. It can then be saved to the target content item. Create a class called **BlockGridTestController.cs** containing the following: - -{% code title="BlockGridTestController.cs" lineNumbers="true" %} -```csharp -using Microsoft.AspNetCore.Mvc; -using My.Site.Models; -using Newtonsoft.Json; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.Controllers; - -namespace My.Site.Controllers; - -public class BlockGridTestController : UmbracoApiController -{ - private readonly IContentService _contentService; - private readonly IContentTypeService _contentTypeService; - - public BlockGridTestController(IContentService contentService, IContentTypeService contentTypeService) - { - _contentService = contentService; - _contentTypeService = contentTypeService; - } - - // POST: /umbraco/api/blockgridtest/create - [HttpPost] - public ActionResult Create() - { - // get the item content to modify - IContent? content = _contentService.GetById(1203); - if (content == null) - { - return NotFound("Could not find the content item to modify"); - } - - // get the element types for spot blocks (content and settings) - IContentType? spotContentType = _contentTypeService.Get("spotElement"); - IContentType? spotSettingsType = _contentTypeService.Get("spotSettings"); - if (spotContentType == null || spotSettingsType == null) - { - return NotFound("Could not find one or more content types for block data"); - } - - // this is the raw data to insert into the block grid - var rawData = new[] - { - new { Title = "Item one", Text = "This is item one", Featured = false, ColumnSpan = 12, RowSpan = 1, ForceLeft = false, ForceRight = false }, - new { Title = "Item two", Text = "This is item two", Featured = true, ColumnSpan = 6, RowSpan = 2, ForceLeft = false, ForceRight = false } - }; - - // build the individual parts of the block grid data from the raw data - var layoutItems = new List(); - var spotContentData = new List(); - var spotSettingsData = new List(); - foreach (var data in rawData) - { - // generate new UDIs for block content and settings - var contentUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); - var settingsUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); - - // create a new layout item - layoutItems.Add(new BlockGridLayoutItem(contentUdi, settingsUdi, data.ColumnSpan, data.RowSpan, data.ForceLeft, data.ForceRight)); - - // create new content data - spotContentData.Add(new BlockGridElementData(spotContentType.Key, contentUdi, new Dictionary - { - { "title", data.Title }, - { "text", data.Text }, - })); - - // create new settings data - spotSettingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsUdi, new Dictionary - { - { "featured", data.Featured ? "1" : "0" }, - })); - } - - // construct the block grid data from layout, content and settings - var blockGridData = new BlockGridData( - new BlockGridLayout(layoutItems.ToArray()), - spotContentData.ToArray(), - spotSettingsData.ToArray()); - - // serialize the block grid data as JSON and save it to the "blockGrid" property on the content item - var propertyValue = JsonConvert.SerializeObject(blockGridData); - content.SetValue("blockGrid", propertyValue); - _contentService.Save(content); - - return Ok("Saved"); - } -} -``` -{% endcode %} - -For the above code `IContent? content = _contentService.GetById(1203);` change the id with your content node that is using the Block Grid. - -10. In order to test this implementation, run the project and add `/umbraco/api/blockgridtest/create` after your domain name. If the result shows as **Saved** then check your content node and you will see the 2 spotElement contents. - -![Block Grid - Result](../../../images/BlockEditorContentCreated.png) - -_This can also be tested via Postman as well if preffered._ \ No newline at end of file diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md deleted file mode 100644 index 3390af9f098..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md +++ /dev/null @@ -1,250 +0,0 @@ -# Block List - -`Alias: Umbraco.BlockList` - -`Returns: IEnumerable` - -**Block List** is a list editing property editor, using [Element Types](../../../../data/defining-content/#what-is-an-element-type) to define the list item schema. - -{% hint style="info" %} -A default Umbraco CMS installation does not ship with a defined _Data Type_ using the Block List editor. In order to start using the property, follow the steps outlined below. - -[Click here for an overview with a worked example and references back to the relevant documention.](https://umbraco.com/blog/deep-dive-the-block-list-editor/) -{% endhint %} - -## Configure Block List - -The Block List property editor is configured in the same way as any standard property editor, via the _Data Types_ admin interface. - -To set up your Block List Editor property, create a new _Data Type_ and select **Block List** from the list of available property editors. - -Then you will see the configuration options for a Block List as shown below. - -![Block List - Data Type Definition](../../built-in-property-editors/block-editor/images/BlockListEditor\_DataType.jpg) - -The Data Type editor allows you to configure the following properties: - -* **Available Blocks** - Here you will define the Block Types to be available for use in the property. Read more on how to set up Block Types below. -* **Amount** - Sets the minimum and/or maximum number of blocks that should be allowed in the list. -* **Single block mode** - When in Single block mode, the output will be `BlockListItem<>` instead of `BlockListModel`- -* **Live editing mode** - Enabling this will make editing of a block happen directly to the document model, making changes appear as you type. -* **Inline editing mode** - Enabling this will change editing experience to inline, meaning that editing the data of blocks happens at sight as accordions. -* **Property editor width** - Overwrite the width of the property editor. This field takes any valid css value for "max-width". - -## Setup Block Types - -Block Types are **Element Types** which need to be created before you can start configuring them as Block Types. This can be done either directly from the property editor setup process, or you can set them up beforehand and add them to the block list after. - -Once you have added an element type as a Block Type on your Block List Data Type you will have the option to configure it further. - -![Block List - Data Type Block Configuration](../../built-in-property-editors/block-editor/images/BlockListEditor\_DataType\_Blocks.png) - -Each Block has a set of properties that are optional to configure. They are described below. - -### Editor Appearance - -By configuring the properties in the group you can customize the user experience for your content editors when they work with the blocks in the Content section. - -* **Label** - Define a label for the appearance of the Block in the editor. The label can use AngularJS template string syntax to display values of properties. [Examples and more details about labels and AngularJS templates.](label-property-configuration.md) -* **Custom view** - Overwrite the AngularJS view for the block presentation in the Content editor. Use this to make a more visual presentation of the block or even make your own editing experience by adding your own AngularJS controller to the view. -* **Custom stylesheet** - Pick your own stylesheet to be used for this block in the Content editor. By adding a stylesheet the styling of this block will become scoped. Meaning that backoffice styles are no longer present for the view of this block. -* **Overlay editor size** - Set the size for the Content editor overlay for editing this block. - -### Data Models - -It is possible to use two separate Element Types for your Block Types. Its required to have one for Content and optional to add one for Settings. - -* **Content model** - This presents the Element Type used as model for the content section of this Block. This cannot be changed, but you can open the Element Type to perform edits or view the properties available. Useful when writing your Label. -* **Settings model** - Add a Settings section to your Block based on a given Element Type. When picked you can open the Element Type or choose to remove the settings section again. - -### Catalogue appearance - -These properties refers to how the Block is presented in the Block catalogue, when editors choose which Blocks to use for their content. - -* **Background color** - Define a background color to be displayed beneath the icon or thumbnail. Eg. `#424242`. -* **Icon color** - Change the color of the Element Type icon. Eg. `#242424`. -* **Thumbnail** - Pick an image or SVG file to replace the icon of this Block in the catalogue. - -The thumbnails for the catalogue are presented in the format of 16:10, and we recommend a resolution of 400px width and 250px height. - -### Advanced - -These properties are relevant when you work with custom views. - -* **Force hide content editor** - If you made a custom view that enables you to edit the content part of a block and you are using default editing mode (not inline) you might want to hide the content-editor from the block editor overlay. - -## Editing Blocks - -When viewing a **Block List** editor in the Content section for the first time, you will be presented with the option to Add content. - -![Block List - Add Content](../../built-in-property-editors/block-editor/images/BlockListEditor\_AddContent.png) - -Clicking the Add content button brings up the Block Catalogue. - -![Block List - Setup](../../built-in-property-editors/block-editor/images/BlockListEditor\_BlockPicker\_simplesetup.jpg) - -The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance. - -![Block List - example setup from Umbraco.com](../../built-in-property-editors/block-editor/images/BlockListEditor\_BlockPicker.jpg) - -Click the Block Type you wish to create and a new Block will appear in the list. - -Depending on whether your Block List Editor is setup to use default or inline editing mode you will see one of the following things happening: - -In default mode you will enter the editing overlay of that Block: - -![Block List - Overlay editing](../../built-in-property-editors/block-editor/images/BlockListEditor\_EditingOverlay.jpg) - -In inline editing mode the new Blocks will expand to show its inline editor: - -![Block List - Inline editing](../../built-in-property-editors/block-editor/images/BlockListEditor\_InlineEditing.jpg) - -More Blocks can be added to the list by clicking the Add content button or using the inline Add content button that appears on hover between or above existing Blocks. - -![Block List - Add Content](../../built-in-property-editors/block-editor/images/BlockListEditor\_AddContentInline.jpg) - -To reorder the Blocks, click and drag a Block up or down to place in the desired order. - -To delete a Block click the trash-bin icon appearing on hover. - -## Rendering Block List Content - -Rendering the stored value of your **Block List** property can be done in two ways. - -### 1. Default rendering - -You can choose to use the built-in rendering mechanism for rendering blocks via a Partial View for each block. - -The default rendering method is named `GetBlockListHtml()` and comes with a few options to go with it. The typical use could be: - -```csharp -@Html.GetBlockListHtml(Model, "MyBlocks") -``` - -"MyBlocks" above is the alias for the Block List editor. - -If using ModelsBuilder the example can be simplified: - -Example: - -```csharp -@Html.GetBlockListHtml(Model.MyBlocks) -``` - -To make this work you will need to create a Partial View for each block, named by the alias of the Element Type that is being used as Content Model. - -These partial views must be placed in this folder: `Views/Partials/BlockList/Components/`. Example: `Views/Partials/BlockList/Components/MyElementTypeAliasOfContent.cshtml`. - -A Partial View will receive the model of `Umbraco.Core.Models.Blocks.BlockListItem`. This gives you the option to access properties of the Content and Settings section of your Block. - -In the following example of a Partial view for a Block Type, please note that the `MyElementTypeAliasOfContent`and `MyElementTypeAliasOfSettings` should correspond with the selected Element Type Alias for the given model in your case. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@{ - var content = (ContentModels.MyElementTypeAliasOfContent)Model.Content; - var settings = (ContentModels.MyElementTypeAliasOfSettings)Model.Settings; -} - -// Output the value of field with alias 'heading' from the Element Type selected as Content section -

@content.Value("heading")

-``` - -With ModelsBuilder: - -```csharp -// Output the value of field with alias 'heading' from the Element Type selected as Content section -

@content.Heading

-``` - -{% embed url="" %} -Working with Block List Editor in Umbraco -{% endembed %} - -### 2. Build your own rendering - -A built-in value converter is available to use the data as you like. Call the `Value` method with a generic type of `IEnumerable` and the stored value will be returned as a list of `BlockListItem` entities. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; -@using Umbraco.Cms.Core.Models.Blocks; -@{ - var blocks = Model.Value>("myBlocksProperty"); - foreach (var block in blocks) - { - var content = block.Content; - - @Html.Partial("MyFolderOfBlocks/" + content.ContentType.Alias, block) - } -} -``` - -Each item is a `BlockListItem` entity that contains two main properties `Content` and `Settings`. Each of these is a `IPublishedElement` which means you can use all the value converters you are used to using. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@using Umbraco.Cms.Core.Models.Blocks; -@{ - var blocks = Model.Value>("myBlocksProperty"); - foreach (var block in blocks) - { - var content = (ContentModels.MyAliasOfContentElementType)block.Content; - var settings = (ContentModels.MyAliasOfSettingsElementType)block.Settings; - -

@content.MyExampleHeadlinePropertyAlias

- } -} -``` - -## Extract Block List Content data - -In some cases, you might want to use the Block List Editor to hold some data and not necessarily render a view since the data should be presented in different areas on a page. An example could be a product page with variants stored in a Block List Editor. - -In this case, you can extract the variant's data using the following, which returns `IEnumerable`. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@using Umbraco.Cms.Core.Models.Blocks; -@{ - var variants = Model.Value>("variants").Select(x => x.Content); - foreach (var variant in variants) - { -

@variant.Value("variantName")

-

@variant.Value("description")

- } -} -``` - -If using ModelsBuilder the example can be simplified: - -Example: - -```csharp -@inherits Umbraco.Web.Mvc.UmbracoViewPage -@using ContentModels = Umbraco.Web.PublishedModels; -@{ - var variants = Model.Variants.Select(x => x.Content).OfType(); - foreach (var variant in variants) - { -

@variant.VariantName

-

@variant.Description - } -} -``` - -If you know the Block List Editor only uses a single block, you can cast the collection to a specific type `T` using `.OfType()` otherwise the return value will be `IEnumerable`. - -## Build a Custom Backoffice View - -Building Custom Views for Block representations in Backoffice is the same for all Block Editors. [Read about building a Custom View for Blocks here](build-custom-view-for-blocks.md) diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/build-custom-view-for-blocks.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/build-custom-view-for-blocks.md deleted file mode 100644 index 5b3ac52cf4e..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/build-custom-view-for-blocks.md +++ /dev/null @@ -1,125 +0,0 @@ -# Build a Custom View for a Block - -You can choose to customize your editing experience by implementing a custom view for each Block Type of a Block Editor. - -By picking a custom view you overwrite the backoffice UI for the given block with your own. This enables you to define how a block should be presented. It can, however, also include interactive elements and be a full custom solution to how data is manipulated. In the Block List Editor the Inline Editing Mode must be disabled for custom backoffice views to appear. - -## Write your own HTML view - -Currently you can only pick HTML files for a custom view. These views are powered by AngularJS and you can write any AngularJS logic. - -Your HTML can be anything. If you use it as a representation of the content you would also want the full view to be clickable. This would then open the default editor for editing of your content. - -The following example displays the property with the alias `headline` together with the `description` inside a button to edit your block. - -```html - -``` - -If you would like to display properties of `settings`, you can access these by using `block.settingsData.myPropertyAlias`. - -## Make Block List Editor custom view draggable - -A custom view of Block List Editor needs to have the 'blockelement\_\_draggable-element' class presented to define which part of the Block that is draggable. - -Example: - -```html - -``` - -## Adding custom implementation to your View - -To achieve this you need to add a custom AngularJS controller to your custom view, using the `ng-controller` attribute: - -```html -

- -
-``` - -Create a folder inside the `App_Plugins` folder called 'CustomBlockView'. - -Create two files within the CustomBlockView file: `package.manifest` and `customBlock.controller.js`. - -Add the following JSON to the `package.manifest` file: - -```json -{ - "javascript": [ - "~/App_Plugins/CustomBlockView/customBlock.controller.js" - ] -} -``` - -{% hint style="info" %} -Umbraco will parse all `package.manifest` files and load any resources they reference into the backoffice during startup. -{% endhint %} - -The second file, `customBlock.controller.js`, will be used to register the 'customBlockController' defined using the `ng-controller` attribute in your custom view. - -To register the controller, add the following lines of code: - -```javascript -angular.module("umbraco").controller("customBlockController", function ($scope) { - // you can do your custom functionality here! -}); -``` - -### Example: Displaying an image from a Media Picker - -Your block may enable you to 'pick' an image for use as the background for a particular block. If you try to display this image directly in the view using `block.data.image`, you will see the unique ID and not the image. - -You will need to use the ID in our custom AngularJS controller in order to get the `ImageUrl` to display in our backoffice Block Editor View. - -With the setup of files above, you need to amend the `customBlock.controller.js` file, by injecting the `mediaResource` to retrieve the image from the ID: - -```javascript -angular.module("umbraco").controller("customBlockController", function ($scope, mediaResource) { - - //your property is called image so the following will contain the udi: - var imageUdi = $scope.block.data.image[0].mediaKey; - //the mediaResource has a getById method: - mediaResource.getById(imageUdi).then(function (media) { - console.log(media); - //set a property on the 'scope' called imageUrl for the returned media object's mediaLink - $scope.imageUrl = media.mediaLink; - }); -}); -``` - -Update the Custom View to use the `imageUrl` property to display the image: - -```html -
-

- -

-
-``` - -If you need to use a specific crop, you can inject the `imageUrlGeneratorResource` resource, which has a `getCropUrl(mediaPath, width, height, imageCropMode, animationProcessMode)` method: - -```javascript -angular.module("umbraco").controller("customBlockController", function ($scope, mediaResource,imageUrlGeneratorResource) { - - //your property is called image so the following will contain the udi: - var imageUdi = $scope.block.data.image[0].mediaKey; - //the mediaResource has a getById method: - mediaResource.getById(imageUdi).then(function (media) { - imageUrlGeneratorResource.getCropUrl(media.mediaLink, 150, 150).then(function (cropUrl) { - console.log(cropUrl); - $scope.imageUrl = cropUrl; - }); - }); -}); -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration.md deleted file mode 100644 index 2fd7181a0b3..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration.md +++ /dev/null @@ -1,63 +0,0 @@ -# Configuring block editor label properties - -When configuring a block, the label property allows you to define a label for the appearance of the Block in the editor. The label can use AngularJS template string syntax to display values of properties. Example: `My Block {{myPropertyAlias}}` will be shown as: `My Block FooBar`. - -You can also use more advanced expressions using AngularJS filters. Example: `{{myPropertyAlias | limitTo:100}}` or for a property using Richtext editor `{{myPropertyAlias | ncRichText | truncate:true:100}}`. - -It is also possible to use properties from the settings model by using `{{$settings.propertyAlias}}`. - -## Useful Angular filters - -As well as the [default AngularJS filters](https://docs.angularjs.org/api/ng/filter), Umbraco ships with some additional filters which are useful for setting the Label field of Block editors. - -| Filter | Description | Property type | Parameters | -| ------------------------------------------------------------ | ------------------------------------------------------- | --------------------------- | ------------------------------------------------------------ | -| ncNodeName | Gets the name of a node | Umbraco node | | -| ncRichText | Strips HTML | Richtext editor | | -| [limitTo](https://docs.angularjs.org/api/ng/filter/limitTo) | AngularJS native truncate | String | n: maximum length of the string | -| [truncate](https://apidocs.umbraco.com/v10/ui/#/api/umbraco.filters.filter:truncate) | Umbraco's richer truncate function | String | wordwise: boolean to indicaste whether to truncate a string mid-word or not
max: maximum length of the string
tail (optional): string to indicate a truncated string, "`…`" by default | -| [umbWordLimit](https://apidocs.umbraco.com/v10/ui/#/api/umbraco.filters.filter:umbWordLimit) | Truncates to a number of words (rather than characters) | String | n: maximum number of words in string | -| [umbCmsTitleCase](https://apidocs.umbraco.com/v10/ui/#/api/umbraco.filters.filter:umbCmsTitleCase) | Converts a string to title case | String | | -| [umbCmsJoinArray](https://apidocs.umbraco.com/v10/ui/#/api/umbraco.filters.filter:umbCmsJoinArray) | Joins an array into one string | Array (of string or object) | separator: string used to join values together, e.g. "`, `"
prop (optional): string key indicating which property to join when used on an array of objects | - -### Custom filters - -If the filters do not suit your needs, you can create custom filters by creating a plugin in `App_Plugins` and adding a filter module. You can see an example below: - -{% hint style="warning" %} -If you do not have an `/App_Plugins` folder, you can create it at the root of your project. -{% endhint %} - -1. Create a plugin by adding a folder inside `App_Plugins` called `MyFilters` -2. Inside the `MyFilters` folder add a `package.manifest` file containing: - -```json -{ - "name": "MyFilters", - "version": "1.0.0", - "allowPackageTelemetry": false, - "javascript": [ - "/App_Plugins/MyFilters/myFilter.filter.js" - ] -} -``` - -3. Add a `myFilter.filter.js` file containing: - -```javascript -angular.module("umbraco.filters").filter("myFilter", function () { - return function (input, parameter1, parameter2, etc) { - // Apply any custom logic to modify the output value and return a string - return `My filter says: "${input}"`; - } -}); -``` - -4. Implement a [block editor](README.md) of your choice. When adding a label add `{{ myFilter }}` which is the property alias of the element type. The `myFilter` property has a `textstring` editor. When adding the content, the block editor will then display the data that you input. - -## Special variables - -| Variable | Description | -| ----------- | ------------------------------------------------------------ | -| `$index` | The 1-based index of this block item in the current block list | -| `$settings` | Provides access to the settings model for the block (if configured) | diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md deleted file mode 100644 index 607939d67f6..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md +++ /dev/null @@ -1,104 +0,0 @@ -# Checkbox List - -`Alias: Umbraco.CheckBoxList` - -`Returns: IEnumerable` - -Displays a list of preset values as a list of checkbox controls. The text saved is an IEnumerable collection of the text values. - -{% hint style="info" %} -Unlike other property editors, the Prevalue IDs are not directly accessible in Razor. -{% endhint %} - -## Data Type Definition Example - -![True/Checkbox List Definition](../built-in-property-editors/images/checkbox-list-setup-v8.png) - -## Content Example - -![Checkbox List Example](../built-in-property-editors/images/checkbox-list-content.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@{ - if (Model.HasValue("superHeros")) - { -
    - @foreach (var item in Model.Value>("superHeros")) - { -
  • @item
  • - } -
- } -} -``` - -### With Modelsbuilder - -```csharp -@{ - if (Model.SuperHeros.Any()) - { -
    - @foreach (var item in Model.SuperHeros) - { -
  • @item
  • - } -
- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@inject IContentService Services; -@using Umbraco.Cms.Core.Services; -@using Newtonsoft.Json -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'superHeros'. - content.SetValue("superHeros", JsonConvert.SerializeObject(new[] { "Umbraco", "CodeGarden"})); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@using Umbraco.Cms.Core.PublishedCache; -@{ - -// Set the value of the property with alias 'superHeros' -content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor,x => x.SuperHeros).Alias, JsonConvert.SerializeObject(new[] { "Umbraco", "CodeGarden"})); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md deleted file mode 100644 index 4e81695ad4b..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md +++ /dev/null @@ -1,102 +0,0 @@ -# Color Picker - -`Alias: Umbraco.ColorPicker` - -`Returns: String (Hexadecimal)` - -`Returns: Umbraco.Cms.Core.PropertyEditors.ValueConverters.ColorPickerValueConverter.PickedColor (When using labels)` - -The Color picker allows you to set some predetermined colors that the editor can choose between. - -It's possible to add a label to use with the color. - -## Data Type Definition Example - -![Color Picker Data Type Definition](../built-in-property-editors/images/Color-Picker-DataType-v10.png) - -## Content Example - -![Color Picker Content](../built-in-property-editors/images/Color-Picker-Content-v8.png) - -## Example with Modelsbuilder - -```csharp -@{ - // Model has a property called "Color" which holds a Color Picker editor - var hexColor = Model.Color; - // Define the label if you've included it - String colorLabel = Model.Color.Label; - - if (hexColor != null) - { -
@colorLabel
- } -} -``` - -## Example without Modelsbuilder - -```csharp -@using Umbraco.Cms.Core.PropertyEditors.ValueConverters -@{ - // Model has a property called "Color" which holds a Color Picker editor - var hexColor = Model.Value("Color"); - // Define the label if you've included it - var colorLabel = Model.Value("Color").Label; - - if (hexColor != null) - { -
@colorLabel
- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@inject IContentService Services; -@using Umbraco.Cms.Core.Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'color'. - // The value set here, needs to be one of the prevalues on the Color Picker - content.SetValue("color", "38761d"); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@using Umbraco.Cms.Core.PublishedCache; -@{ - // Set the value of the property with alias 'color' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Color).Alias, "38761d"); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md deleted file mode 100644 index 6dfe04ded0f..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md +++ /dev/null @@ -1,99 +0,0 @@ -# Content Picker - -`Alias: Umbraco.ContentPicker` - -`Returns: IPublishedContent` - -The content picker opens a panel to pick a specific page from the content structure. The value saved is the selected nodes [UDI](../../../../reference/querying/udi-identifiers.md) - -## Data Type Definition Example - -![Content Picker Data Type Definition](../built-in-property-editors/images/Content-Picker2-DataType-v10.png) - -## Content Example - -![Content Picker Content](../built-in-property-editors/images/Content-Picker-Content-v10.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@{ - IPublishedContent typedContentPicker = Model.Value("featurePicker"); - if (typedContentPicker != null) - { -

@typedContentPicker.Name

- } -} -``` - -### With Modelsbuilder - -```csharp -@{ - IPublishedContent typedContentPicker = Model.FeaturePicker; - if (typedContentPicker != null) - { -

@typedContentPicker.Name

- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; - -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Get the page you want to assign to the content picker - var page = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45"); - - // Create an Udi of the page - var udi = Udi.Create(Constants.UdiEntityType.Document, page.Key); - - // Set the value of the property with alias 'featurePicker'. - content.SetValue("featurePicker", udi.ToString()); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@using Umbraco.Cms.Core; - -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'featurePicker' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.FeaturePicker).Alias, udi.ToString()); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md deleted file mode 100644 index d3f3c07320b..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md +++ /dev/null @@ -1,85 +0,0 @@ -# DateTime - -`Alias: Umbraco.DateTime` - -`Returns: DateTime` - -Displays a calendar UI for selecting dates which are saved as a DateTime value. - -## Data Type Definition Example - -![Data Type Definition Example](../built-in-property-editors/images/date-time-v8.png) - -There are two settings available for manipulating the DateTime property. - -One is to set a format. By default the format of the date in the Umbraco backoffice will be `YYYY-MM-DD HH:mm:ss`, but you can change this to something else. See [MomentJS.com](https://momentjs.com/) for the supported formats. - -The second setting is "Offset time". When enabling this setting the displayed time will be offset with the servers timezone. This can be useful in cases where an editor is in a different timezone than the hosted server. - -## Content Example - -![Content Example](../built-in-property-editors/images/date-picker-v8.png) - -## MVC View Example - displays a datetime - -### With Modelsbuilder - -```csharp -@Model.DatePicker -``` - -### Without Modelsbuilder - -```csharp -@Model.Value("datePicker") -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@inject IContentService Services; -@using Umbraco.Cms.Core.Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'datePicker' - content.SetValue("datePicker", DateTime.Now); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - - // Set the value of the property with alias 'datePicker' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.DatePicker).Alias, DateTime.Now); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md deleted file mode 100644 index 28130e6cefb..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md +++ /dev/null @@ -1,35 +0,0 @@ -# Date - -`Returns: Date` - -Displays a calendar UI for selecting dates which are saved as a DateTime value. - -## Data Type Definition Example - -![Data Type Definition Example](../built-in-property-editors/images/DateTime-DataType.png) - -The only setting that is available for manipulating the Date property is to set a format. By default the format of the date in the Umbraco backoffice will be `YYYY-MM-DD`, but you can change this to something else. See [MomentJS.com](https://momentjs.com/) for the supported formats. - -## Content Example - -![Content Example](../built-in-property-editors/images/Date-Time-Content.png) - -## MVC View Example - displays a datetime - -### Typed - -```csharp -@(Model.Content.GetPropertyValue("datePicker").ToString("dd MM yyyy")) -``` - -### Dynamic (Obsolete) - -{% hint style="warning" %} -See [Common pitfalls](../../../../reference/common-pitfalls.md) for more information about why the dynamic approach is obsolete. -{% endhint %} - -```csharp -@{ - @CurrentPage.datePicker.ToString("dd-MM-yyyy") -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md deleted file mode 100644 index 7786c581e39..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md +++ /dev/null @@ -1,82 +0,0 @@ -# Decimal - -`Alias: Umbraco.Decimal` - -`Returns: decimal` - -## Data Type Definition Example - -![Data Type Definition Example](../built-in-property-editors/images/definition-example.png) - -In the example above the possible values for the input field would be \[8, 8.5, 9, 9.5, 10] - -_All other values will be removed in the content editor when saving or publishing._ - -If the value of **Step Size** is not set then all decimal values between 8 and 10 is possible to input in the content editor. - -## Content Example - -![Content Example](../built-in-property-editors/images/content-example.png) - -## MVC View Example - -### With Modelsbuilder - -```csharp -@Model.MyDecimal -``` - -### Without Modelsbuilder - -```csharp -@Model.Value("MyDecimal") -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@inject IContentService Services; -@using Umbraco.Cms.Core.Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'myDecimal'. - content.SetValue("myDecimal", 3); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@using Umbraco.Cms.Core.PublishedCache; -@{ - // Set the value of the property with alias 'myDecimal' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.MyDecimal).Alias, 3); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md deleted file mode 100644 index e3de29c0a12..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md +++ /dev/null @@ -1,130 +0,0 @@ -# Dropdown - -`Alias: Umbraco.DropDown.Flexible` - -`Returns: String` or `IEnumerable` - -Displays a list of preset values. Either a single value or multiple values (formatted as a collection of strings) can be returned. - -## Settings - -### Enable multiple choice - -If enabled, editors will be able to select multiple values from the dropdown otherwise only a single value can be selected. - -### Prevalues - -Prevalues are the options which are shown in the dropdown list. You can add, edit, or remove values here. - -## Data Type Definition Example - -![Dropdown Data Type Definition](../../built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png) - -## Content Example - -### Single Value - -![Single dropdown content example](../../built-in-property-editors/dropdown/images/DropdownSingle-Content.png) - -### Multiple Values - -![Multiple dropdown content example](../../built-in-property-editors/dropdown/images/DropdownMultiple-Content.png) - -## MVC View Example - -### Single item - without Modelsbuilder - -```csharp -@if (Model.HasValue("category")) -{ -

@(Model.Value("category"))

-} -``` - -### Multiple items - without Modelsbuilder - -```csharp -@if (Model.HasValue("categories")) -{ - var categories = Model.Value>("categories"); -
    - @foreach (var category in categories) - { -
  • @category
  • - } -
-} -``` - -### Single item - with Modelsbuilder - -```csharp -@if (!Model.HasValue(Model.Category)) -{ -

@Model.Category

-} -``` - -### Multiple items - with Modelsbuilder - -```csharp -@if (Model.Categories.Any()) -{ -
    - @foreach (var category in Model.Categories) - { -
  • @category
  • - } -
-} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@using Newtonsoft.Json -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'categories'. - content.SetValue("categories", JsonConvert.SerializeObject(new[] { "News" })); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'categories' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Categories).Alias, JsonConvert.SerializeObject(new[] { "News" })); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md deleted file mode 100644 index fd7e8ece5da..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -meta.Title: Display an email address -description: In this article you can learn how to use the build in email property editor ---- - -# Email Address - -`Alias: Umbraco.EmailAddress` - -`Returns: String` - -Displays an email address. - -## Settings - -The Email Address Property Editor does not come with any further configuration. The property can be configured once it has been added to a Document Type. - -![Mandatory Checkbox Example](../built-in-property-editors/images/emailaddress-datatype-v10.png) - -## Content Example - -![Single email address content example](../built-in-property-editors/images/EmailAddress-Content-v10.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@if (Model.HasValue("email")) -{ - var emailAddress = Model.Value("email"); -

@emailAddress

-} -``` - -### With Modelsbuilder - -```csharp -@if (!string.IsNullOrWhiteSpace(Model.Email)) -{ -

@Model.Email

-} -``` - -## Add value programmatically - -See the example below to learn how a value can be added or changed programmatically to an Email-address property. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; - -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of your page - var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); - - // Get the page using the GUID you've just defined - var content = contentService.GetById(guid); - // Set the value of the property with alias 'email' - content.SetValue("email", "jpk@umbraco.dk"); - - // Save the change - contentService.Save(content); -} -``` - -{% hint style="info" %} -The value sent to an EmailAddress property needs to be a correct email address, For example: name@domain.com. - -It is recommended that you set up validation on this property, in order to verify whether the value added is in the correct format. -{% endhint %} diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md deleted file mode 100644 index f5a4ea2afd6..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md +++ /dev/null @@ -1,93 +0,0 @@ -# Eye Dropper Color Picker - -`Alias: Umbraco.ColorPicker.EyeDropper` - -`Returns: string` - -The Eye Dropper Color picker allows you to choose a color from the full color spectrum using HEX and RGBA. - -## Data Type Definition Example - -![Eye Dropper Color Picker Data Type Definition](../built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png) - -## Content Example - -![Eye Dropper Color Picker Content](../built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png) - -## Example with Modelsbuilder - -```csharp -@{ - var color = Model.Color?.ToString(); - - if (color != null) - { - - } -} -``` - -## Example without Modelsbuilder - -```csharp -@{ - var color = Model.Value("Color"); - - if (color != null) - { - - } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'color'. - content.SetValue("color", "#6fa8dc"); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'color' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Color).Alias, "#6fa8dc"); - - // Set the value of the property with alias 'theme' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Theme).Alias, "rgba(111, 168, 220, 0.7)"); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md deleted file mode 100644 index 0574991ef34..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md +++ /dev/null @@ -1,139 +0,0 @@ -# File Upload - -`Alias: Umbraco.UploadField` - -`Returns: string` - -Adds an upload field, which allows documents or images to be uploaded to Umbraco. - -You can define which file types should be accepted through the upload field. - -{% hint style="info" %} -For uploading and adding files and images to your Umbraco project, we recommend using the Media Picker. - -Find the full documentation for the property in the [Media Picker](media-picker-3.md) article. -{% endhint %} - -## Data Type Definition Example - -![Data Type Definition Example](../built-in-property-editors/images/definition-example-v10.png) - -## Content Example - -![Content Example Empty](../built-in-property-editors/images/content-example-empty.png) ![Content Example](../built-in-property-editors/images/File-Upload-content-example.png) - -In code, the property is a string, which references the location of the file. - -Example: `"/media/o01axaqu/guidelines-on-remote-working.pdf"` - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@using System.IO; -@{ - if (Model.HasValue("myFile")) - { - var myFile = Model.Value("myFile"); - - @System.IO.Path.GetFileName(myFile) - } - -} -``` - -### With Modelsbuilder - -```csharp -@if (!Model.HasValue(Model.MyFile)) -{ - @System.IO.Path.GetFileName(Model.MyFile) -} -``` - -## Add values programmatically - -{% hint style="info" %} -The samples in this section have not been verified against the latest version of Umbraco. - -Instead, we recommend using the [Media Picker](media-picker-3.md) for uploading files to your Umbraco website. -{% endhint %} - -See the example below to see how a value can be added or changed programmatically. To update a value of this property editor you need the [Content Service](../../../../reference/management/services/contentservice/) and the [Media Service](../../../../reference/management/services/mediaservice.md). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.IO -@using Umbraco.Cms.Core.Serialization -@using Umbraco.Cms.Core.Strings -@inject MediaFileManager _mediaFileManager; -@inject IShortStringHelper _shortStringHelper; -@inject IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; -@inject IContentService Services; -@inject IJsonSerializer _serializer; -@inject MediaUrlGeneratorCollection _mediaUrlGeneratorCollection; - -@{ - // Get access to ContentService - var contentService = Services; - - // Get access to MediaService - var mediaService = MediaService; - - // Create a variable for the GUID of the parent where you want to add a child item - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Create a variable for the file you want to upload, in this case the Our Umbraco logo - var imageUrl = "https://our.umbraco.com/assets/images/logo.svg"; - - // Create a request to get the file - var request = WebRequest.Create(imageUrl); - var webResponse = request.GetResponse(); - var responseStream = webResponse.GetResponseStream(); - - // Get the file name - var lastIndex = imageUrl.LastIndexOf("/", StringComparison.Ordinal) + 1; - var filename = imageUrl.Substring(lastIndex, imageUrl.Length - lastIndex); - - // Create a media file - var media = mediaService.CreateMediaWithIdentity("myImage", -1, "File"); - media.SetValue(_mediaFileManager, _mediaUrlGeneratorCollection, _shortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File, filename, responseStream); - // Save the created media - mediaService.Save(media); - - // Get the published version of the media (IPublishedContent) - var publishedMedia = Umbraco.Media(media.Id); - - // Set the value of the property with alias 'myFile' - content.SetValue("myFile", publishedMedia.Url()); - - // Save the child item - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'myFile' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.MyFile).Alias, publishedMedia.Url(); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/README.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/README.md deleted file mode 100644 index c41fcdf35c7..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Grid Layout - -`Returns: JSON` - -Gives editors a grid layout editor which allows them to insert different types of content in a predefined layout. - -
- -## [What are Grid Layouts](what-are-grid-layouts.md) - -The basic concept of Grid Layouts. - -## [Configuring the Grid Layout data type](configuring-the-grid-layout-datatype.md) - -How to setup your Grid Layout data type. - -## [Settings and styling](settings-and-styles.md) - -Add settings and styles. - -## [Grid editors](grid-editors.md) - -Explanation of default Grid editors and how to customise them. - -## [Build your own Grid editor](build-your-own-editor.md) - -Build your own Grid editor from the ground up. - -## [Render Grid in template](render-grid-in-template.md) - -Render content created with Grid Layouts in your templates. - -## [Grid Layout Best Practices](grid-layout-best-practices.md) - -General guidelines when contemplating Grid Layout implementation. - -## [Add values programmatically](add-value-programmatically.md) - -Example how to add values programmatically. diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/add-value-programmatically.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/add-value-programmatically.md deleted file mode 100644 index 5e9a2457c68..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/add-value-programmatically.md +++ /dev/null @@ -1,96 +0,0 @@ -# Add Values Programmatically - -## Configuration - -For this example, the default grid configuration has been used. - -![Grid configuration](../../built-in-property-editors/grid-layout/Images/Grid-configuration.jpg) - -## Set value - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../../reference/management/services/contentservice/). - -```csharp -@using Newtonsoft.Json -@using Umbraco.Cms.Core.Services; -@using Umbraco.Cms.Core.Models; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Create a variable for the grid value with the 1 one column layout and add a headline - var gridValue = new GridValue - { - Name = "1 column layout", - Sections = new List - { - new GridValue.GridSection - { - Rows = new List - { - new GridValue.GridRow - { - Name = "Headline", - Id = new Guid(), - Areas = new List - { - new GridValue.GridArea - { - Controls = new List - { - new GridValue.GridControl - { - Editor = new GridValue.GridEditor - { - Alias = "headline" - }, - Value = "Our Umbraco" - } - } - } - - } - } - } - - } - } - }; - - // Serialize the grid value - var serializedGridValue = JsonConvert.SerializeObject(gridValue); - - // Set the value of the property with alias 'body' - content.SetValue("body", serializedGridValue); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'body' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Body).Alias, serializedGridValue); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/build-your-own-editor.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/build-your-own-editor.md deleted file mode 100644 index a8814ad600d..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/build-your-own-editor.md +++ /dev/null @@ -1,130 +0,0 @@ -# Build your own editor - -{% hint style="info" %} -The samples in this section have not been verified against the latest version of Umbraco. - -A new Property Editor called the **Block based Grid editor** will soon be available as a substitute for the existing Grid Layout editor. For more information, see the [Block based Grid editor for Umbraco CMS](https://umbraco.com/products/roadmap/) in the Umbraco Roadmap. -{% endhint %} - -Create a file in `/App_Plugins/yourpackage/editor.html` and add the following to the editor.html file: - -```html - -``` - -Save the file and add an editor to the `/App_Plugins/yourpackage/package.manifest` file: - -```json -{ - "gridEditors": [ - { - "name": "Code", - "alias": "code", - "view": "/App_Plugins/yourpackage/editor.html", - "icon": "icon-code", - "config": { - "color": "red", - "text-align": "right" - } - } - ] -} -``` - -Add a new file: `/App_Plugins/yourpackage/editor.cshtml` - this file will handle rendering the entered data - this path is done by convention so: - -- view: 'editor' => `views/partials/grid/editors/editor.cshtml` -- view: '/App_Plugins/path.html' => `/App_Plugins/path.cshtml` - -If you wish to use something entirely different you can give the editor a separate `render` value which follow the same conventions. - -```json -{ - "name": "Code", - "alias": "code", - "view": "/App_Plugins/yourpackage/editor.html", - "render": "/App_Plugins/yourpackage/custom-render.cshtml" -} -``` - -## Grid editor controller - -If you are building something slightly more complex then a text area, you will need to add a controller to the grid editor view. So first add a ng-controller attribute to the grid editor html - this works like building a property editor: - -```html -
- -
-``` - -To wire up a controller to this view, create the file `/App_Plugins/yourpackage/editor.controller.js` and add a standard angular controller declaration: - -```js -angular.module("umbraco").controller("my.custom.grideditorcontroller", function ($scope) { - $scope.control.value = "my new value"; -}); -``` - -Finally, we need to tell Umbraco to load this JavaScript controller when the Umbraco application boots. This is like building a property editor. Add your JavaScript (and css dependencies) in the `package.manifest` file in the `/yourpackage` folder, and configure it to load your controller file. - -```json -{ - "gridEditors": [ - { - "name": "Code", - "alias": "code", - "view": "/App_Plugins/yourpackage/editor.html", - "icon": "icon-code", - "config": { - "color": "red", - "text-align": "right" - } - } - ], - javascript:[ - "/App_Plugins/yourpackage/editor.controller.js" - ] -} -``` - -So to summarize, to create a custom grid editor from scratch, you will need to: - -- Create a grid editor view `.html` file -- Create a grid render `.cshtml` file -- Create a grid editor controller `.js` file -- Create a `package.manifest` to register the editor and make Umbraco load needed files - -This process tries to be as close to building property editors as currently possible. - -### Rendering grid editor content - -Next add this c# to the .cshtml file: - -```csharp -@inherits Umbraco.Web.Mvc.UmbracoViewPage -
@Model
-``` - -When rendering the .cshtml file will receive a dynamic model with the raw data of the editor: - -```json -{ - "value": "What ever value entered into the textarea", - "editor": { - "name": "Code", - "alias": "code", - "view": "/App_Plugins/yourpackage/editor.html", - "icon": "icon-code", - "config": { - "color": "red", - "text-align": "right" - } - } -} -``` - -So you can now use these value to build your razor output like so: - -```html -
@Model.value
-``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/configuring-the-grid-layout-datatype.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/configuring-the-grid-layout-datatype.md deleted file mode 100644 index 059e744ec40..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/configuring-the-grid-layout-datatype.md +++ /dev/null @@ -1,30 +0,0 @@ -# Configuring The Grid Layout - -A grid layout contains multiple configuration options to allow developers to tailor the grid to a very specific site design. Configuring the layout can be divided into 2 overall parts: - -## Layouts - -A layout is the general grid "container", it contains one or more sections which content editors can use to insert preconfigured **rows**. There are 2 main usage scenarios of layouts: - -1. A single column layout which to the content editor will act like a full page canvas to insert elements on -2. A multiple column layout with a main content body, and one or more sidebar columns to insert lists or other sidebar widgets on. - -
- -You can however configure as many layouts and layout sections as you wish, each section in the layout must be given a width in columns, so editors gets an accurate preview of their layout. - -
- -## Row configurations - -A row in the grid editor contains one or more cells, which divide the row into areas where editors can enter content. So a row is merely a container of areas to insert content into. When you add a new row, you are asked to give it a name, then define cells inside the row by clicking the "+" icon. Each cell has a default width set to 4, but by clicking the inserted cell you can control its width. - -It is possible to setup configurable attributes(class, rel, href) and inline styling on rows. - -
- -You can add as many cells as you like. If they overflow the total width of the row, they will be arranged after each other horizontally as you'd expect in a grid system. - -
- -Each cell can by default contain any type of editor such as textstring editors, imagespicker, embedded media or Umbraco macros. To override this behavior, uncheck the **allow all editors** option and you can specify which editors will be available for the row. diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors.md deleted file mode 100644 index 4027a167635..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors.md +++ /dev/null @@ -1,198 +0,0 @@ -# Grid Editors - -A grid editor is the component responsible for getting data into the grid - that could be a text field or a media picker. They're built in the same way as a property editor thus consists of 3 parts: - -* .html view file -* .js controller -* .cshtml server side renderer - -The view is what the editor sees, the controller handles how it acts and the cshtml determines how the entered data is rendered in the template. - -## Default configuration - -Grid editors are specified in `/config/grid.editors.config.js`. By default this file doesn't exist, so before you attempt to extend the configuration, make sure to create it first. - -The default items in the config file are as follows below. It is recommended that you copy all of editors below before you add more, in case some of them are already in use. - -If you don't add the editors below to this config file then they won't be available in your grid editors, even if there are existing grid datatypes already using these editors. - -{% hint style="info" %} -You will need to restart your site before any new customizations become available to use. -{% endhint %} - -```json -[ - { - "name": "Rich text editor", - "alias": "rte", - "view": "rte", - "icon": "icon-article" - }, - { - "name": "Image", - "nameTemplate": "{{ value && value.udi ? (value.udi | ncNodeName) : '' }}", - "alias": "media", - "view": "media", - "icon": "icon-picture" - }, - { - "name": "Macro", - "nameTemplate": "{{ value && value.macroAlias ? value.macroAlias : '' }}", - "alias": "macro", - "view": "macro", - "icon": "icon-settings-alt" - }, - { - "name": "Embed", - "alias": "embed", - "view": "embed", - "icon": "icon-movie-alt" - }, - { - "name": "Headline", - "nameTemplate": "{{ value }}", - "alias": "headline", - "view": "textstring", - "icon": "icon-coin", - "config": { - "style": "font-size: 36px; line-height: 45px; font-weight: bold", - "markup": "

#value#

" - } - }, - { - "name": "Quote", - "nameTemplate": "{{ value ? value.substring(0,32) + (value.length > 32 ? '...' : '') : '' }}", - "alias": "quote", - "view": "textstring", - "icon": "icon-quote", - "config": { - "style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-style: italic; font-size: 18px", - "markup": "
#value#
" - } - } -] -``` - -### Default Grid editors - -Grid editor are created in the JSON format and each editor is an object like so: - -```json -{ - "name": "Rich text editor", - "alias": "rte", - "view": "rte", - "icon": "icon-article" -} -``` - -### Custom Grid editors - -You can customize the built-in editors to tailor the grid to your need. - -#### package.manifest - -It is recommended that you define custom editors in a `package.manifest` file (not in the config file described above) like so: - -```json -{ - "gridEditors": - [ - { - "name": "Rich text editor", - "alias": "rte", - "view": "rte", - "icon": "icon-article" - } - ] -} -``` - -While the root JSON element of `/config/grid.editors.config.js` is an array of grid editors, `package.manifest` files start with a JSON object with a number of different properties - one of them being `gridEditors`. - -The package manifest should be placed in a folder inside the `/App_Plugins/` folder - for instance `/App_Plugins/{YourPackageName}/package.manifest`. You can define as many grid editors you want and it can be done over multiple manifests so you can use grid editors from packages etc. With the `package.manifest` file in place, Umbraco will automatically pick it up during startup. - -You can read more about `package.manifest` files in general at the [Package Manifest](../../../../../extending/property-editors/package-manifest.md) page. - -**Grid editor configuration** - -For a grid editor, the required values are: - -* `name`: The name of the editor -* `alias`: Unique alias of the editor -* `icon`: Icon shown to the editor, uses same icon classes as the rest of -* `view` the view defines the editor used to enter a value. By default Umbraco will look in `/umbraco/views/propertyeditors/grid/editors` for a html view to use - but you can pass in your own path - -{% hint style="info" %} -You can also add a name template for generating grid item labels using the syntax `{{ value.propertyAlias }}`. - -* If you would like to include the index position in the label, you can use `{{$index}}`. -* If your editor links to a content, media or member node, you can use the Angular filter `{{ value.udi | ncNodeName }}` to show the node name rather than the node ID. -* If your editor is a rich text editor, you can use the Angular filter `{{ value | ncRichText }}` to show the unformatted text. -{% endhint %} - -The built-in views you can use are: - -* `textstring` -* `rte` -* `embed` -* `macro` -* `media` - -In most cases you will either use the textstring or media view, or built your own from scratch. The textstring and media editors come with some additional configuration to make it quick to customise these. - -**Sample textstring config** - -```json -{ - "name": "Headline", - "alias": "headline", - "view": "textstring", - "icon": "icon-coin", - "config": { - "style": "font-size: 36px; line-height: 45px; font-weight: bold", - "markup": "

#value#

" - } -} -``` - -In this sample, the `config.style` value is applied to the editor so users can see an accurate preview in the backoffice. This will be applied as as inline styling to the textarea in the backoffice. - -The `config.markup` is the string rendered server side in your template. `#value#`will be replaced with the actual value - -**Sample media config** - -```json -{ - "name": "Square Image", - "alias": "squareImage", - "view": "media", - "icon": "icon-picture", - "config": { - "size": { - "height": 200, - "width": 200 - } - } -} -``` - -In this sample `config.size` will resize the image according to `height` and `width`. The above example will result in a rendered image that is 200x200 pixels no matter the size of the uploaded image. If the ratio of the size differs from the uploaded image it is possible to set a focal point that determines how the image should be cropped. - -
- -**Sample macro config** - -```json -{ - "name": "Your Custom Macro", - "alias": "yourCustomMacroGridEditor", - "view": "macro", - "icon": "icon-smiley", - "config": { - "macroAlias": "AliasOfYourMacro" - } -} -``` - -In this sample a new option will appear in the `Choose type of content` with direct access to the macro. diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-layout-best-practices.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-layout-best-practices.md deleted file mode 100644 index 35a6ff9b758..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-layout-best-practices.md +++ /dev/null @@ -1,33 +0,0 @@ -# Grid Layout Best Practices - -_The grid layout editor offers non-technical editors a more visual editing environment to layout content pages and enter content of many different kinds._ - -The editor offers many configuration options, and as a website implementor, you could be tempted to use the grid for nearly every kind of content entry - this is however not encouraged. - -To help developers determine when to use the grid layout, we've outlined the 2 major use-cases below. - -## 1. As a RTE Replacement - -The grid should primarily be used to replace content entry in a rich text editor (RTE). Where editors before would struggle with aligning images, lists and text or using tables inside the editor to layout content in columns. - -The grid solves this scenario, giving editors predefined layouts and editors to enter content. They do not have to worry about how the content is rendered, since everything is stored in a very semantic format passing on that responsibility to the developer implementing the website. - -## 2. Managing widgets - -Another common scenario the grid layout editor supports are managing and inserting widgets on a page. Using the grid, editors can pick pre-made components, either text, images, embedded elements or macros and insert them in a sidebar on the page. - -This could replace various setups involving content pickers, repeatable content editors and other kinds of collections of content nodes and macros. - -### Limitations - -With the above usage scenarios in mind, consider the grids limitations. First of all, all content entered into the grid is stored as a single property value on the content node, as a big JSON object. This means that as soon as the values are stored in the database, there is no managed API to drill into the grid content and target specific cell content. A grid layout is not a recommended storage of reusable content - it wasn't designed for this scenario. If you wish to reuse content in multiple pages, it is still recommended that you store these pieces of content as separate content nodes, so they can be stored, cached and queried as usual. - -### Customisation - -Keep all customisation in the `/App_Plugins/` folder. This makes it easier to share across multiple projects and ensures that nothing is lost in an update process. - -### Keep it basic - -The grid cannot solve every problem, neither was it meant to. It absolutely shines when configured correctly and designed to solve well-defined editor tasks, like entering content in a pre-defined layout and preconfigured options. If you put a standard grid editor on every page, expecting editors to do magic, you will be disappointed - and so will your editor. - -So keep the use cases basic, spend time to configure and tune the grid in detail, this will truly make your editors love you. diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/render-grid-in-template.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/render-grid-in-template.md deleted file mode 100644 index 88202034b49..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/render-grid-in-template.md +++ /dev/null @@ -1,29 +0,0 @@ -# Render grid in template - -## Using @Html.GetGridHtml - -To render a property based on the grid inside a template you should use the HtmlHelper extension: - -```csharp -@Html.GetGridHtml(Model, "propertyAlias") -``` - -This will render the grid item with alias "propertyAlias" from the current page models' content. - -This will by default use the view `/views/partials/grid/bootstrap3.cshtml` you can also use other provided grid template rendering files - for example the built-in bootstrap2.cshtml view by overloading this helper: - -```csharp -@Html.GetGridHtml(Model, "propertyAlias", "bootstrap3") -``` - -You can create your own custom grid rendering files e.g for your favourite or custom grid framework implementation. Tip: copy one of the existing files as a starting point. By convention, if you create your "mycustomrenderer.cshtml" file in `/views/partials/grid` you can render the grid property like so: - -```csharp -@Html.GetGridHtml(Model, "propertyAlias", "mycustomrenderer") -``` - -or alternatively you can provide the path to where the file resides: - -```csharp -@Html.GetGridHtml(Model, "propertyAlias", "/views/mycustomrenderer.cshtml") -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/settings-and-styles.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/settings-and-styles.md deleted file mode 100644 index a771e66bbb4..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/settings-and-styles.md +++ /dev/null @@ -1,180 +0,0 @@ -# Settings And Styling - -A grid layout can also expose custom settings - such as data-attributes or styling options - on each cell or row. This allows editors to use a friendly UI to add configuration values to grid elements. When custom settings and styles are applied, they will by default be included in the grid html as either html attributes or inline styles. - -
- -These settings and styles must be configured by developers when setting up the grid layout data type. - -## Configuring a custom setting or style - -To add a setting, click the edit settings link. This will expand a dialog showing you the raw configuration data. This data is in the JSON format and will only save if it's valid JSON. - -The settings data could look like this, with an object for each setting: - -```json -[ - { - "label": "Class", - "description": "Set a css class", - "key": "class", - "view": "textstring", - "modifier": "col-sm-{0}", - "applyTo": "row|cell" - } -] -``` - -The different values are: - -* `label` : Field name displayed in the content editor UI -* `description` : Descriptive text displayed in the content editor UI to guide the user -* `key` : The key the entered setting value will be stored under. -* `view` : The editor used to enter a setting value with. -* `prevalues` : For views that need predefined values, e.g. the radiobuttonlist view. -* `modifier (optional)` : A string formatter to modify the output of the editor to prepend or append extra values. -* `applyTo (optional)` : States whether the setting can be used on a cell or a row. If either not present or empty, the setting will be shown both on Rows and Cells. - -**label** and **description** are straight-forward. - -**key** defines the alias the configuration is stored under and by default the alias of the attribute will also be the attribute on the rendered html element. In the example above any value entered in this settings editor will be rendered in the grid html as: - -```html -
-``` - -By changing the key of the setting you can modify the `
` element's attributes like `class`, `title`, `id` or custom `data-*` attributes. - -**view** the view defines the editor used to enter a value. By default Umbraco comes with a collection of prevalue editors: - -* `textstring` -* `textarea` -* `radiobuttonlist` -* `mediapicker` -* `imagepicker` -* `boolean` -* `treepicker` -* `treesource` -* `number` -* `multivalues` - -Alternatively you can also pass in a path to a custom view like "/App\_Plugins/grid/editors/view.html" - -**prevalues** is for views that need predefined values, e.g. the radiobuttonlist view. Prevalues are defined as strings in an array: - -```json -"prevalues": [ - "value_1", - "value_2", - "value_3" -] -``` - -and will translate in to three different options where each string will become a radiobutton. The strings represent the value of the options. - -Prevalues can also be defined as an object of label/value allowing to have a displayed label instead of showing the actual underlying value. You can even mix and match these and use both label/value prevalues and string prevalues in the same configuration: - -```json -"prevalues": [ - { - "label": "Value one", - "value": "value_1" - }, - { - "label": "Value two", - "value": "value_2" - }, - "value_3" -] -``` - -**modifier** is a basic way to prepend, append or wrap the value from the editor in a string. This is especially useful when working with custom styles which often requires additional values to function. For instance if you want to set a background image you can get an image path from the image picker view. But in order for it to work with css it has to be wrapped in `url()`. In that case you set the **modifier** to `url({0})` which means that `{0}` is replaced with the editor value. - -**applyTo** defines what this setting can be applied to. It should be either **row** or **cell** as a string. - -A JSON object can also be used if you need a more specific configuration. A JSON configuration could look like this: - -```json -"applyTo": { - "row": "Headline,Article", - "cell": "4,8,6" -} -``` - -This would ensure the setting can only be used on rows named **Article** or **Headline**, or on cells sized: **4**, **8** or **6**. If it should only apply to cells you can remove the row property. If it should apply to all rows you can specify it by having the row property with null or an empty string as value. - -### Sample settings - -There are many ways to combine these, here are some samples: - -#### Set a background image style - -```json -{ - "label": "Background image", - "description": "Choose an image", - "key": "background-image", - "view": "imagepicker", - "modifier": "url('{0}')" -} -``` - -#### Set a title setting - -```json -{ - "label": "Title", - "description": "Set a title on this element", - "key": "title", - "view": "textstring" -} -``` - -#### Set a data-custom setting - -```json -{ - "label": "Custom data", - "description": "Set the custom data on this element", - "key": "data-custom", - "view": "radiobuttonlist", - "prevalues": [ - "value_1", - "value_2", - "value_3" - ] -} -``` - -### Multiple settings and styles - -You can add multiple settings and styles configurations on a data type. This is done by creating a new setting or style object. Remember to separate the objects with a comma. - -#### Adding multiple settings - -```json -[ - { - "label": "Class", - "description": "Set a class on this element", - "key": "class", - "view": "textstring" - }, - { - "label": "Title", - "description": "Set a title on this element", - "key": "title", - "view": "textstring" - }, - { - "label": "Custom data", - "description": "Set the custom data on this element", - "key": "data-custom", - "view": "textstring" - } -] -``` - -### Full-width settings and styles - -It is possible to use settings and styles to add full-width background-images, background-colors and so forth. Make sure the surrounding _section_ is full-width (12 columns by default) and the _rows_ inside it will automatically become full-width. diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/what-are-grid-layouts.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/what-are-grid-layouts.md deleted file mode 100644 index 4d526a5442c..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/what-are-grid-layouts.md +++ /dev/null @@ -1,17 +0,0 @@ -# What Are Grid Layouts? - -To understand how the grid layout editor works, we must first understand the structure of the grid layouts. - -Grid layouts consists of two main areas that need to be configured, _grid layout area_ and _grid rows_. - -## Grid Layout - -The _layout area_ is where the overall page layout is defined. _Layout areas_ are divided in to _layout sections_ e.g. a sidebar section and content section. The size of the _layout sections_ is defined in columns. For a full-width content area use max number of columns (12 for Bootstrap 3). Each _layout section_ contains one or more _rows_. - -
- -### Grid Rows - -Grid _rows_ is where the actual content goes. Each row is divided into _cells_ that contain the property editors. The size of the cells is defined in columns. Unlike the _layouts sections_ it is possible to add more _cells_ than the max number of columns - they will stack as they should in a grid system. - -
diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md deleted file mode 100644 index 3d84e6a5fd4..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md +++ /dev/null @@ -1,340 +0,0 @@ -# Image Cropper - -`Returns: MediaWithCrops` - -Returns a path to an image, along with information about focal point and available crops. - -When the Image Cropper is used on a Media Type the crops are shared between all usages of a Media Item. This is called **global crops**. - -If the Image Cropper is used on a Document Type, the file and crops will be **local** to the Document. - -Notice that it is possible make local crops on shared Media Items via the [Media Picker Property Editor](media-picker-3.md). - -## Settings - -### Prevalues - -You can add, edit & delete crop presets the cropper UI can use. - -## Data Type Definition Example - -![Image Cropper Data Type Definition](../built-in-property-editors/images/imageCropper-v9.png) - -## Content Example - -The Image Cropper provides a UI to upload an image, set a focal point on the image, and use predefined crops. - -By default, images in the Image Cropper will be shown based on a set focal point and only use specific crops if they are available. - -The Image Cropper comes with 3 modes: - -* Uploading an image -* Setting a focal point -* Cropping the image to predefined crops - -### Uploading images - -The editor exposes a drop area for files. Select it to upload an image. - -![Image Cropper Upload](../built-in-property-editors/images/imageCropper-upload-v8.png) - -### Set focal point - -By default, the Image Cropper allows the editor to set a focal point on the uploaded image. - -All the preset crops are shown to give the editor a preview of what the image will look like on the frontend. - -![Image Cropper Focal point](../built-in-property-editors/images/imageCropper-focalpoint-v8.png) - -### Crop and resize - -The editor can fit the crop to the image to ensure that the image is presented as intended. - -![Image Cropper Crop](../built-in-property-editors/images/imageCropper-crop-v8.png) - -## Powered by ImageSharp.Web - -[ImageSharp.Web](https://sixlabors.com/products/imagesharp-web/) is image processing middleware for ASP.NET. - -We bundle this package with Umbraco and you can therefore take full advantage of all its features for resizing and format changing. Learn more about the built in processing commands in [the official ImageSharp documentation](https://docs.sixlabors.com/articles/imagesharp.web/processingcommands.html). - -## Sample code - -The Image Cropper comes with an API to generate crop URLs. You can also access the raw data directly as a dynamic object. - -For rendering a cropped media item, the `.GetCropUrl` is used: - -```html - -``` - -The third parameter is `HtmlEncode` and is by default set to true. This means you only need to define the parameter if you want to disable HTML encoding. - -### Example to output a "banner" crop from a cropper property with the property alias "customCropper" - -```html - -``` - -Or, alternatively using the `MediaWithCrops` extension method: - -```html - -``` - -### Example to dynamically create a crop using the focal point - in this case 300 x 400px image - -```csharp -@if (Model.Photo is not null) -{ - @Model.Photo.Name -} -``` - -### CSS background example to output a "banner" crop - -Set the `htmlEncode` to false so that the URL is not HTML encoded - -```csharp -@if (Model.Photo is not null) -{ - var cropUrl = Url.GetCropUrl(Model.Photo, "square", false); - -
-} -``` - -## Add values programmatically - -To update a content property value you need the [Content Service](../../../../reference/management/services/contentservice/). - -The following sample demonstrates how to add or change the value of an Image Cropper property programmatically. The sample creates an API controller with an action, which must be invoked via a POST request to the URL written above the action. - -{% tabs %} -{% tab title="Latest version" %} -```csharp -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PropertyEditors.ValueConverters; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.Controllers; -using Umbraco.Extensions; - -namespace Umbraco.Docs.Samples.Web.Property_Editors_Add_Values; - -public class CreateImageCropperValuesController : UmbracoApiController -{ - private readonly IContentService _contentService; - private readonly IMediaService _mediaService; - private readonly MediaUrlGeneratorCollection _mediaUrlGeneratorCollection; - - - public CreateImageCropperValuesController( - IContentService contentService, - IMediaService mediaService, - MediaUrlGeneratorCollection mediaUrlGeneratorCollection) - { - _contentService = contentService; - _mediaService = mediaService; - _mediaUrlGeneratorCollection = mediaUrlGeneratorCollection; - } - - // /Umbraco/Api/CreateImageCropperValues/CreateImageCropperValues - [HttpPost] - public ActionResult CreateImageCropperValues() - { - // Create a variable for the GUID of the page you want to update - var contentKey = Guid.Parse("89974f8b-e213-4c32-9f7a-40522d87aa2f"); - - // Get the page using the GUID you've defined - IContent? content = _contentService.GetById(contentKey); - if (content == null) - { - return false; - } - - // Create a variable for the GUID of the media item you want to use - var mediaKey = Guid.Parse("b6d4e98a-07c0-45f9-bfcc-52994f2806b6"); - - // Get the desired media file - IMedia? media = _mediaService.GetById(mediaKey); - if (media == null) - { - return false; - } - - // Create a variable for the image cropper and set the source - var imageCropperValue = new ImageCropperValue - { - Src = media.GetUrl("umbracoFile", _mediaUrlGeneratorCollection) - }; - - // Serialize the image cropper value - var propertyValue = JsonConvert.SerializeObject(imageCropperValue); - - // Set the value of the property with alias "cropper" - // - remember to add the "culture" parameter if "cropper" is set to vary by culture - content.SetValue("cropper", propertyValue); - - return _contentService.Save(content).Success; - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -using System; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PropertyEditors.ValueConverters; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.Controllers; -using Umbraco.Extensions; - -namespace Umbraco.Docs.Samples.Web.Property_Editors_Add_Values -{ - public class CreateImageCropperValuesController : UmbracoApiController - { - private IContentService _contentService; - private IMediaService _mediaService; - private MediaUrlGeneratorCollection _mediaUrlGeneratorCollection; - - - public CreateImageCropperValuesController(IContentService contentService, IMediaService mediaService, MediaUrlGeneratorCollection mediaUrlGeneratorCollection) - { - _contentService = contentService; - _mediaService = mediaService; - _mediaUrlGeneratorCollection = mediaUrlGeneratorCollection; - } - - // /Umbraco/Api/CreateImageCropperValues/CreateImageCropperValues - [HttpGet] - public ActionResult CreateImageCropperValues() - { - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("4e96411a-b8e1-435f-9322-2faee30ef5f2"); - - // Get the page using the GUID you've defined - var content = _contentService.GetById(guid); // ID of your page - - // Create a variable for the GUID of the media item you want to use - var mediaKey = Guid.Parse("cf1ab8dc-ad0f-4a8e-974b-87b84777b0d6"); - - // Get the desired media file - var media = _mediaService.GetById(mediaKey); - - // Create a variable for the image cropper and set the source - var cropper = new ImageCropperValue {Src = media.GetUrl("umbracoFile", _mediaUrlGeneratorCollection)}; - - // Serialize the image cropper value - var cropperValue = JsonConvert.SerializeObject(cropper); - - // Set the value of the property with alias 'cropper' - content.SetValue("testCropper", cropperValue, "en-US"); - - return _contentService.Save(content).Success.ToString(); - } - } -} -``` -{% endtab %} -{% endtabs %} - -If you use Models Builder to generate source code (modes `SourceCodeAuto` or `SourceCodeManual`), you can use `nameof([generated property name])` to access the desired property without using a magic string: - -{% tabs %} -{% tab title="Latest version" %} -```csharp -// Set the value of the "Cropper" property on content of type MyContentType -// - remember to add the "culture" parameter if "cropper" is set to vary by culture -content.SetValue(nameof(MyContentType.Cropper).ToFirstLowerInvariant(), propertyValue); -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -@{ - // Set the value of the property with alias 'cropper' - content.SetValue(Product.GetModelPropertyType(_publishedSnapshotAccessor, x => x.TestCropper).Alias, cropperValue, "en-US"); -} -``` -{% endtab %} -{% endtabs %} - -## Get all the crop urls for a specific image - -Crop URLs are not limited to usage within a view. `IPublishedContent` has a `GetCropUrl` extension method, which can be used to access crop URLs anywhere. - -The following sample demonstrates how to use `GetCropUrl` to retrieve URLs for all crops defined on a specific image: - -{% tabs %} -{% tab title="Latest version" %} -```csharp -public Dictionary GetCropUrls(IPublishedContent image) -{ - // Get the Image Cropper property value for property with alias "umbracoFile" - ImageCropperValue? imageCropperValue = image.Value("umbracoFile"); - if (imageCropperValue?.Crops == null) - { - return new Dictionary(); - } - - // Return all crop aliases and their corresponding crop URLs as a dictionary - var cropUrls = new Dictionary(); - foreach (ImageCropperValue.ImageCropperCrop crop in imageCropperValue.Crops) - { - // Get the cropped URL and add it to the dictionary that I will return - var cropUrl = crop.Alias != null - ? image.GetCropUrl(crop.Alias) - : null; - if (cropUrl != null) - { - cropUrls.Add(crop.Alias!, cropUrl); - } - } - - return cropUrls; -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -internal Dictionary GetCropUrls(IPublishedContent image) -{ - //Instantiate the dictionary that I will return with "Crop alias" and "Cropped URL" - Dictionary cropUrls = new Dictionary(); - - if (image.HasValue("umbracoFile")) - { - var imageCropper = image.Value("umbracoFile"); - foreach (var crop in imageCropper.Crops) - { - //Get the cropped URL and add it to the dictionary that I will return - cropUrls.Add(crop.Alias, image.GetCropUrl(crop.Alias)); - } - } - - return cropUrls; -} -``` -{% endtab %} -{% endtabs %} - -## Sample on how to change the format of the image - -Below the example to output a PNG using ImageSharp.Web [format](https://docs.sixlabors.com/articles/imagesharp.web/processingcommands.html#format) command. - -```html - -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md deleted file mode 100644 index 17d1d48c635..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md +++ /dev/null @@ -1,93 +0,0 @@ -# Label - -`Alias: Umbraco.Label` - -`Returns: String` - -Label is a non-editable control and can only be used to display a pre-set value. - -## Data Type Definition Example - -![Label Data Type Definition](../built-in-property-editors/images/Label-Setup-v8.png) - -### Value type - -If you want to set a value other than a String, you can define the data using one of the other available Data Types. These include Decimal, Date/time, Time, Integer, and Big integer. - -There is also a Value Type: Long string if you need to set a long string value for your Label. - -## Content Example - -![Label Content Example](../built-in-property-editors/images/Label-Content-v8.png) - -## MVC View Example - -### Without ModelsBuilder - -```csharp -@{ - if (Model.HasValue("pageLabel")){ -

@(Model.Value("pageLabel"))

- } -} -``` - -### With ModelsBuilder - -```csharp -@{ - if (!string.IsNullOrEmpty(Model.PageLabel)) - { -

@Model.PageLabel

- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@{ - @inject IContentService Services; - - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'pageLabel'. - content.SetValue("pageLabel", "A pre-set string value"); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@{ - @inject IPublishedSnapshotAccessor _publishedSnapshotAccessor - - // Set the value of the property with alias 'pageLabel' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.MyLabel).Alias, "A Preset string"); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/listview.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/listview.md deleted file mode 100644 index d5a9dc1fecc..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/listview.md +++ /dev/null @@ -1,109 +0,0 @@ -# List View - -`Alias: Umbraco.Listview` - -`Returns: IEnumerable` - -**List View** display a list of categories when it is enabled on a Document Type that has children. - -![List view example](../built-in-property-editors/images/listview.png) - -## Enable list view - -If enabled, editors will be able to see multiple children from a list on a content node that has children. When not enabled, no list will be shown and all children will be shown in the Content Tree. - -![Enable List view example](../built-in-property-editors/images/enable-listview.png) - -## Settings - -![List view settings example](../built-in-property-editors/images/list-view-settings1-v10.png) ![List view settings example 2](../built-in-property-editors/images/list-view-settings2-v10.png) - -### Page Size - -Defines how many child content nodes you want to see per page. This will limit how many content items you will see in your list. If you set it to 5, then only 5 content items will be shown in the list. - -### Order By - -Will sort your list by the selection you choose in the dropdown. By default it selects "Last edited" and you get the following three columns: - -* **Last edited** - When the content node was last edited and saved. -* **Name** - Name of the content node(s). -* **Created by** - This is the user who the content node was created by. - -You can add more sorting to this list by adding more datatypes to the columns in the "Columns Displayed" section. - -### Order Direction - -You can select order of the content nodes displayed, "Acsending" or "Descending". The order is affected by the "Order By" selection. - -### Columns Displayed - -It is possible to add more columns to the list, via adding the properties through the dropdown. These properties are based on the Data Types which are used by the Document Type. It will show up in the dropdown by its alias and not the name on the property. - -![List view property example](../built-in-property-editors/images/listview-property.png) ![List view property example](../built-in-property-editors/images/listview-property-dropdown.png) - -Once you have selected a column that you want to display, the next thing you want to do is define what its name should be and what kind of value it should display. You can also move the headers around, re-ordering how the headers should look. This is done by the move icon on the left side of the alias. - -The template section is where you define what kind of value you want to display. The value of the column is in the `value` variable. - -### Layouts - -The list view comes with two layouts by default. A list and a grid view. These views can be disabled if you are not interested in any of them. - -{% hint style="info" %} -A minimum of one layout needs to be enabled for the list view to work. -{% endhint %} - -You can also make your own layout and add it to the settings. For example, if you wanted to change the width or length of the grid, you will be able to do so. - -### Bulk Action Permissions - -Select what kind of action is available on the list view. - -* **Allow bulk publish** - content only -* **Allow bulk unpublish** - content only -* **Allow bulk copy** - content only -* **Allow bulk move** -* **Allow bulk delete** - -### Content app icon - -Changes the icon in the backoffice of the listview. By default it will look like the image below. - -![List icon example](../built-in-property-editors/images/list-icon.png) - -### Content app name - -You can change the name of the listview itself. Default if empty: 'Child Items'. - -### Show Content App First - -Enable this to show the content app by default instead of the list view - -## Content Example - -### Generic field value - -This example uses a generic field on a child item and displays it in the list. ![List view content example email](../built-in-property-editors/images/listview-content-example-email-settings.png) - -The `{{ value }}` will take the value of the Email property and display it in the list, as shown on the image below. - -![List view content example email](../built-in-property-editors/images/listview-content-example-email.png) - -### Member name - -First, a Member Picker property needs to be present on the content item. In this example, the `child item` has gotten a Member Picker Data Type with the alias of `isAuthor`. - -![List view member picker](../built-in-property-editors/images/member-picker.png) - -Now that the child item has a member and the value that should be displayed is the name of the picked value, the next step is to reconfigure the template value in the listview setting. - -![List view member picker](../built-in-property-editors/images/member-picker-settings.png) - -This will take the value picked up by the member picker. ![List view member picker](../built-in-property-editors/images/picked-member.png) - -And display it in the listview. Shown in the example below: ![List view member picker](../built-in-property-editors/images/list-member-picked.png) - -### Other examples - -![List view other examples](../built-in-property-editors/images/others.png) ![List view other examples](../built-in-property-editors/images/others-result.png) diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md deleted file mode 100644 index e205efda9d1..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md +++ /dev/null @@ -1,112 +0,0 @@ -# Markdown Editor - -`Alias: Umbraco.MarkdownEditor` - -`Returns: System.Web.HtmlString` - -This built-in editor allow the user to use the markdown formatting options, from within a tinyMCE-like interface. - -## Data Type Definition Example - -![Definition Example](../built-in-property-editors/images/Markdown-Editor-definition-example-v10.png) - -There are three settings available for manipulating the **Markdown editor** property. - -* **Preview** toggles if a preview of the markdown should be displayed beneath the editor in the content view. -* **Default value** is inserted if no content has been saved to the Document Type using this property editor. -* **Overlay Size** is used to select the width of the link picker overlay in the content view. - -## Content Example - -![Content Example](../built-in-property-editors/images/Markdown-Editor-content-example.png) - -### Explanation of buttons from left to right - -| Function | Shortcut | Further explanation | -| --------------------- | -------- | -------------------------------------- | -| toggle **bold** text | Ctrl + B | | -| toggle _italic_ text | Ctrl + I | | -| insert link | Ctrl + L | This opens the Select Link interface. | -| toggle quote | Ctrl + Q | | -| toggle code block | Ctrl + K | | -| insert image | Ctrl + G | This opens the Select Media interface. | -| toggle ordered list | Ctrl + O | | -| toggle unordered list | Ctrl + U | | -| toggle heading | Ctrl + H | This toggles between h1, h2 and off. | -| toggle a hr | | | -| undo | Ctrl + Z | | -| redo | Ctrl + Y | | - -### Other functionality - -| Function | Shortcut | -| ---------- | -------- | -| select all | Ctrl + A | -| copy | Ctrl + C | -| paste | Ctrl + V | - -## MVC View Example - -### With Modelsbuilder - -```csharp -@Model.MyMarkdownEditor -``` - -### Without Modelsbuilder - -```csharp -@Model.Value("MyMarkdownEditor") -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Create markdown value - var markdownValue = new HtmlString("#heading \n**strong text**"); - - // Set the value of the property with alias 'myMarkdownEditor'. - content.SetValue("myMarkdownEditor", markdownValue); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'myMarkdownEditor' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.MyMarkdownEditor).Alias, markdownValue); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md deleted file mode 100644 index 480860c2003..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md +++ /dev/null @@ -1,196 +0,0 @@ -# Media Picker - -`Alias: Umbraco.MediaPicker3` - -`Returns: IEnumerable` or `MediaWithCrops` - -This property editors returns a single `MediaWithCrops` item if the "Pick multiple items" Data Type setting is disabled or a collection if it is enabled. - -## Data Type Definition Example - -![Media Picker Data Type Definition](../built-in-property-editors/images/MediaPicker-DataType-v10.png) - -### Accepted types - -Use setting to limit the picker to only select Media Items of these types. - -### Pick multiple items - -Use this setting to enable the property to contain multiple items. When this is enabled the property editor returns an `IEnumerable`. - -You can still set the maximum amount to 1. Do so when you want to retrieve a collection but only allow the Content Editors to select one Media Item. - -### Amount - -Use this setting to enforce a minimum and/or maximum amount of selected Media Items. - -{% hint style="info" %} -It is not possible to set a maximum amount when the "Pick multiple items" feature is disabled. -{% endhint %} - -### Start node - -This setting is used to limit the Media Picker to certain parts of the Media Tree. - -### Ignorer user start nodes - -Use this setting to overrule user permissions, to enable any user of this property to pick any Media Item of the chosen Start node. - -When this setting is enabled, a user can access the media available under the selected "Start Node" (/Design in this case). This applies even if they normally lack access. The access is granted specifically when using this particular Media Picker. - -### Enable Focal Point - -Enable the focal point setter, do only enable this if the focal point is used or if you have Image crops defined. - -### Image Crops - -Define local image crops. Local image crop data is stored on the document in this property. This means it can differentiate between documents. - -This is different from Global crops as they are defined on the Media Item, making the crops shared between all usage of that Media Item. - -Global crops are configured on the Image Cropper property of the Image Media Type - -[Read about the Image Cropper here](image-cropper.md) - -## Content Example - -![Media Picker Content](../built-in-property-editors/images/Media-Picker3-Content.jpg) - -## MVC View Example - -### Multiple enabled without Modelsbuilder - -```csharp -@using Umbraco.Cms.Core.Models -@{ - var typedMultiMediaPicker = Model.Value>("medias"); - foreach (var entry in typedMultiMediaPicker) - { - - } -} -``` - -### Multiple enabled with Modelsbuilder - -```csharp -@{ - var typedMultiMediaPicker = Model.Medias; - foreach (var entry in typedMultiMediaPicker) - { - - } -} -``` - -### Multiple disabled without Modelsbuilder - -```csharp -@using Umbraco.Cms.Core.Models -@{ - var typedMediaPickerSingle = Model.Value("media"); - if (typedMediaPickerSingle != null) - { - @typedMediaPickerSingle.Value( - } -} -``` - -### Multiple disabled with Modelsbuilder - -```csharp -@using Umbraco.Cms.Core.Models -@{ - var typedMediaPickerSingle = Model.Media; - if (typedMediaPickerSingle is MediaWithCrops mediaEntry) - { - - } -} -``` - -## Using crops - -Both local and global crops are retrieved using the method `GetCropUrl`. If crops with identical aliases are defined both locally and globally, the locally defined crops are always prioritized by `GetCropUrl`. - -The following is an example of how to retrieve a crop from a `MediaWithCrops` entry: - -```csharp -@{ - foreach (var entry in Model.Medias) - { - - } -} -``` - -### Explicitly retrieving global crops - -You can retrieve globally defined crops explicitly by using `GetCropUrl` on the `UrlHelper`: - -```csharp -@{ - foreach (var entry in Model.Medias) - { - - } -} -``` - -### Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -The following sample will update a single image in a Media Picker. - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core; -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Get the media you want to assign to the media picker - var media = Umbraco.Media("bca8d5fa-de0a-4f2b-9520-02118d8329a8"); - - // Create an Udi of the media - var udi = Udi.Create(Constants.UdiEntityType.Media, media.Key); - - // Set the value of the property with alias 'featuredBanner'. - content.SetValue("featuredBanner", udi.ToString()); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'featuredBanner' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.FeaturedBanner).Alias, udi.ToString()); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker.md deleted file mode 100644 index b6345799e7a..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker.md +++ /dev/null @@ -1,135 +0,0 @@ -# Media Picker (Legacy) - -{% hint style="info" %} -We highly recommend that you use the [Media Picker](media-picker-3.md) instead. - -This updated property contains more customizable features, and we recommend using this over the Media Picker, which is also marked as the _old_ version of the picker. -{% endhint %} - -`Alias: Umbraco.MediaPicker` - -`Returns: IEnumerable` or `IPublishedContent` - -This property editors returns a single item if the "Pick multiple items" Data Type setting is disabled or a collection if it is enabled. - -## Data Type Definition Example - -![Media Picker Data Type Definition](../built-in-property-editors/images/Media-Picker-DataType-v10.png) - -### Ignore user start nodes - -Use **Settings** to overrule user permissions, to enable any user of this property to pick any Media Item of the choosen Start node. - -When this setting is enabled, a user who doesn't normally have access to the media selected as "Start Node" (/Design in this case), can access the media when using this particular Media Picker. If no Start node has been defined for this property any content can be viewed and selected of this property. - -## Content Example - -![Media Picker Content](../built-in-property-editors/images/Media-Picker-Content-v8.png) - -## MVC View Example - -### Multiple enabled without Modelsbuilder - -```csharp -@{ - var typedMultiMediaPicker = Model.Value>("sliders"); - foreach (var item in typedMultiMediaPicker) - { - - } -} -``` - -### Multiple enabled with Modelsbuilder - -```csharp -@{ - var typedMultiMediaPicker = Model.Sliders; - foreach (var item in typedMultiMediaPicker) - { - - } -} -``` - -## Multiple disabled without Modelsbuilder - -```csharp -@{ - var typedMediaPickerSingle = Model.Value("featuredBanner"); - if (typedMediaPickerSingle != null) - { -

@typedMediaPickerSingle.Url()

- @typedMediaPickerSingle.Value( - } -} -``` - -## Multiple disabled with Modelsbuilder - -```csharp -@{ - var typedMediaPickerSingle = Model.FeaturedBanner; - if (typedMediaPickerSingle is Image image) - { -

@image.Url()

- - } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core; -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Get the media you want to assign to the media picker - var media = Umbraco.Media("bca8d5fa-de0a-4f2b-9520-02118d8329a8"); - - // Create an Udi of the media - var udi = Udi.Create(Constants.UdiEntityType.Media, media.Key); - - // Set the value of the property with alias 'featuredBanner'. - content.SetValue("featuredBanner", udi.ToString()); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'featuredBanner' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.FeaturedBanner).Alias, udi.ToString()); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md deleted file mode 100644 index 8ea46e67385..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md +++ /dev/null @@ -1,97 +0,0 @@ -# Member Group Picker - -`Alias: Umbraco.MemberGroupPicker` - -`Returns: string` - -The Member Group Picker opens a panel to pick one or more member groups from the Member section. The value saved is of type string (comma separated IDs). - -## Data Type Definition Example - -![Member Group Picker Type Definition](../built-in-property-editors/images/Member-Picker-DataType.png) - -## Content Example - -![Member Grouep Picker Content](../built-in-property-editors/images/Member-Group-Picker-Content.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@if (Model.HasValue("memberGroup")) -{ - var memberGroup = Model.Value("memberGroup"); -

@memberGroup

-} -``` - -### With Modelsbuilder - -```csharp -@if (!string.IsNullOrEmpty(Model.MemberGroup)) -{ -

@Model.MemberGroup

-} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; - -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'memberGroup'. The value is the specific ID of the member group - content.SetValue("memberGroup", 1067); - - // Save the change - contentService.Save(content); -} -``` - -You can also add multiple groups by creating a comma separated string with the desired member group IDs. - -```csharp -@{ - // Set the value of the property with alias 'memberGroup'. - content.SetValue("memberGroup", "1067","1068"); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@using Umbraco.Cms.Core; - -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'memberGroup' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.MemberGroup).Alias, 1067); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md deleted file mode 100644 index 73b36f9cf24..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md +++ /dev/null @@ -1,98 +0,0 @@ -# Member Picker - -`Alias: Umbraco.MemberPicker` - -`Returns: IPublishedContent` - -The member picker opens a panel to pick a specific member from the member section. The value saved is of type IPublishedContent. - -## Data Type Definition Example - -![Media Picker Data Type Definition](../built-in-property-editors/images/Member-Picker-DataType-v8.png) - -## Content Example - -![Member Picker Content](../built-in-property-editors/images/Member-Picker-Content-v8.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@{ - if (Model.HasValue("author")) - { - var member = Model.Value("author"); - @member.Name - } -} -``` - -### With Modelsbuilder - -```csharp -@{ - if (Model.Author != null) - { - var member = Model.Author; - @member.Name - } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; - -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Create a variable for the GUID of the member ID - var authorId = Guid.Parse("ed944097281e4492bcdf783355219450"); - - // Set the value of the property with alias 'author'. - content.SetValue("author", authorId); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@using Umbraco.Cms.Core; - -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - var udi = Udi.Create(Constants.UdiEntityType.Member, authorId); - - // Set the value of the property with alias 'author' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Author).Alias, udi); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md deleted file mode 100644 index e38c6b531ce..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md +++ /dev/null @@ -1,147 +0,0 @@ -# Multi Url Picker - -`Alias: Umbraco.MultiUrlPicker` - -`Returns: IEnumerable or Link` - -Multi Url Picker allows an editor to pick and sort multiple urls. This property editor returns a single item if the "Maximum number of items" Data Type setting is set to 1 or a collection if it is 0. These can either be internal, external or media. - -## Data Type Definition Example - -![Related Links Data Type Definition](../built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png) - -## Content Example - -![Media Picker Content](../built-in-property-editors/images/Multy-Url-Picker-Content-v8.png) - -## MVC View Example - value converters enabled - -## Typed - -```csharp -@using Umbraco.Cms.Core.Models -@{ - var links = Model.Value>("footerLinks"); - if (links.Any()) - { -
    - @foreach (var link in links) - { -
  • @link.Name
  • - } -
- } -} -``` - -If `Max number of items` is configured to `1` - -```csharp -@using Umbraco.Cms.Core.Models -@{ - var link = Model.Value("link"); - if (link != null) - { - @link.Name - } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core; -@using Umbraco.Cms.Core.Services; -@using Newtonsoft.Json; -@using Umbraco.Cms.Core.Models; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Get the media you want to assign to the footer links property - var media = Umbraco.Media("bca8d5fa-de0a-4f2b-9520-02118d8329a8"); - - // Create an Udi of the media - var mediaUdi = Udi.Create(Constants.UdiEntityType.Media, media.Key); - - // Get the content you want to assign to the footer links property - var contentPage = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45"); - - // Create an Udi of the Content - var contentPageUdi = Udi.Create(Constants.UdiEntityType.Document, contentPage.Key); - - // Create a list with different link types - var externalLink = new List - { - // External Link - new Link - { - Target = "_blank", - Name = "Our Umbraco", - Url = "https://our.umbraco.com/", - Type = LinkType.External - }, - // Media - new Link - { - Target = "_self", - Name = media.Name, - Url = media.MediaUrl(), - Type = LinkType.Media, - Udi = mediaUdi - }, - // Content - new Link - { - Target = "_self", - Name = contentPage.Name, - Url = contentPage.Url(), - Type = LinkType.Content, - Udi = contentPageUdi - } - }; - - // Serialize the list with links to JSON - var links = JsonConvert.SerializeObject(externalLink); - - - // Set the value of the property with alias 'footerLinks'. - content.SetValue("footerLinks", links); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'footerLinks' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.FooterLinks).Alias, links); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multinode-treepicker.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multinode-treepicker.md deleted file mode 100644 index d389aea6eac..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multinode-treepicker.md +++ /dev/null @@ -1,133 +0,0 @@ -# Multinode Treepicker - -`Alias: Umbraco.MultiNodeTreePicker` - -`Returns: IEnumerable` - -## Settings - -The Multinode Treepicker allows you to configure the type of tree to render and what part of the tree that should be rendered. For content it allows you to select a dynamic root node based on the current document using the multinode tree picker. - -**Node type:** set the type of node, the root node of the tree, or query for the root node - -For querying for a root node, you can use dynamic placeholders in the XPath query, following the below sample queries - -``` -// get the first textpage below the current document -$current/textpage: current page or closest found ancestor - -// get a descendant of type news article somewhere below the parent -$parent//newsArticle: parent page or closest found ancestor - -// go to the root of the content tree -$root - -// go the ancestor at @level=1 where your website root usually is. -$site: Ancestor node at level 1 -``` - -It is important to notice that all placeholders above act against published content only. So if you, therefore, try to fetch `$parent` of the current document, then Umbraco will return that or its closest published ancestor. So in case, the parent is not published, it will try the parent of that parent, and so on. - -**Filter out items with type:** allow or disallow tree nodes with a certain content type alias. - -Enter `typeAlias,altTypeAlias` to only allow selecting nodes with those alias'. Enter `!typeAlias,altTypeAlias` to only allow selecting nodes **not** with those alias'. - -**Minimum/maximum number of items:** set a limit on the number of items allowed to be selected. - -## Data Type Definition Example - -![Multinode Treepicker Data Type Definition](../built-in-property-editors/images/Multinode-Treepicker-DataType-8\_1.png) - -## Content Example - -![Multinode Treepicker](../built-in-property-editors/images/Multinode-Treepicker-Content-v8.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@{ - var typedMultiNodeTreePicker = Model.Value>("featuredArticles"); - if (typedMultiNodeTreePicker != null) { - foreach (var item in typedMultiNodeTreePicker) - { -

@item.Name

- } -} -``` - -### With Modelsbuilder - -```csharp -@{ - var typedMultiNodeTreePicker = Model.FeaturedArticles; - foreach (var item in typedMultiNodeTreePicker) - { -

@item.Name

- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@inject IContentService Services; -@using Umbraco.Cms.Core; -@using Umbraco.Cms.Core.Services - -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Get the pages you want to assign to the Multinode Treepicker - var page = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45"); - var anotherPage = Umbraco.Content("1f8cabd5-2b06-4ca1-9ed5-fbf14d300d59"); - - // Create Udi's of the pages - var pageUdi = Udi.Create(Constants.UdiEntityType.Document, page.Key); - var anotherPageUdi = Udi.Create(Constants.UdiEntityType.Document, anotherPage.Key); - - // Create a list of the page udi's - var udis = new List{pageUdi.ToString(), anotherPageUdi.ToString()}; - - // Set the value of the property with alias 'featuredArticles'. - content.SetValue("featuredArticles", string.Join(",", udis)); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@using Umbraco.Cms.Core.PublishedCache; - -@{ - // Set the value of the property with alias 'featuredArticles' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor ,x => x.FeaturedArticles).Alias, string.Join(",", udis)); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md deleted file mode 100644 index ad6760644f5..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md +++ /dev/null @@ -1,102 +0,0 @@ -# Repeatable Textstrings - -`Alias: Umbraco.MultipleTextstring` - -`Returns: array of strings` - -The Repeatable textstrings property editor enables a content editor to make a list of text items. For best use with an unordered-list. - -## Data Type Definition Example - -![Repeatable textstrings Data Type Definition](../built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png) - -## Content Example - -![Repeatable textstrings Content](<../built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1) (1).png>) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@{ - if (Model.Value("keyFeatureList").Length > 0) - { -
    - @foreach (var item in Model.Value("keyFeatureList")) - { -
  • @item
  • - } -
- } -} -``` - -### With Modelsbuilder - -```csharp -@{ - if (Model.KeyFeatureList.Any()) - { -
    - @foreach (var item in Model.KeyFeatureList) - { -
  • @item
  • - } -
- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'keyFeatureList' - content.SetValue("keyFeatureList", "Awesome" + Environment.NewLine + "Super"); - - // Save the change - contentService.Save(content); -} -``` - -{% hint style="info" %} -To add multiple values to the repeatable text strings property editor you have to put each value on a new line. This can be achieved using either `\r\n\` or `Environment.NewLine`. -{% endhint %} - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'keyFeatureList' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.KeyFeatureList).Alias, "Awesome" + Environment.NewLine + "Super"); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/nested-content.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/nested-content.md deleted file mode 100644 index 62cb1914a28..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/nested-content.md +++ /dev/null @@ -1,208 +0,0 @@ -# Nested Content - -{% hint style="info" %} -We highly recommend that you use the [Block List](block-editor/block-list-editor.md) instead. - -Nested Content has been marked as obsolete and development on the property editor has been discontinued. - -[Umbraco Deploy](https://docs.umbraco.com/umbraco-deploy/deployment-workflow/import-export/import-with-migrations) and [uSync migrations](https://github.com/Jumoo/uSyncMigrations) have support for migrating from nested content to the block list. -{% endhint %} - -`Alias: Umbraco.NestedContent` - -`Returns: IEnumerable` (or `IPublishedElement` depending on configuration) - -**Nested Content** is a list editing property editor, using Element Types to define the list item schema. By using Document Types you have the benefit of a reusable UI that you are familiar with and get to re-use all the standard Data Types as field editors. This property editor returns either a single item or a collection of this Document Type. - -The Element Types that Nested Content uses are specialized Document Types - they can be found in the same section as Document Types. However, it is not possible to create content directly in the content tree with an Element Type - it is meant to be used in complex editors like Nested Content or Blocklist. - -## Configuring Nested Content - -The **Nested Content** property editor is set-up/configured in the same way as any standard property editor, via the _Data Types_ admin interface. To set-up your Nested Content property, create a new _Data Type_ and select **Nested Content** from the list of available property editors. - -You should then be presented with the **Nested Content** property editors Data Type editor as shown below. - -![Nested Content - Data Type Definition](../built-in-property-editors/images/NestedContent\_DataType-v8.png) - -The Data Type editor allows you to configure the following properties: - -* **Doc Types** - Defines a list of Document Types to use as data blueprints for this **Nested Content** instance. For each Document Type, you can provide the alias of the group you wish to render (the first group is used by default if not set) as well as a template for generating list item labels using the syntax `{{propertyAlias}}`. - * If you would like to include the Document Type name in the label, you can use `{{alias}}`. - * If you would like to include the index position in the label, you can use `{{$index}}`. - * If your property links to a content, media or member node, you can use the Angular filter `{{ pickerAlias | ncNodeName }}` to show the node name rather than the node ID. - * If your property is a rich text editor, you can use the Angular filter `{{ pickerAlias | ncRichText }}` to show the unformatted text. - * You can use conditional logic to show text instead of 1 or 0 for a true/false property: `{{checkboxPickerAlias == 1 ? 'Yes' : 'No'}}`. - * For more complex property types, you can display specific attributes by referencing the JSON attribute. For example, if using the MultiUrlPicker, show the name of the first link using `{{urlPickerAlias[0]["name"]}}`. - * [Examples and more details about labels and AngularJS templates](block-editor/label-property-configuration.md) -* **Min Items** - Sets the minimum number of items that should be allowed in the list. If greater than `0`, **Nested Content** will pre-populate your list with the minimum amount of allowed items and prevent deleting items below this level. Defaults to `0`. -* **Max Items** - Sets the maximum number of items that should be allowed in the list. If greater than `0`, **Nested Content** will prevent new items being added to the list above this threshold. Defaults to `0`. -* **Confirm Deletes** - Enabling this will demand item deletions to require a confirmation before being deleted. Defaults to `true`. -* **Show Icons** - Enabling this will display the item's Document Type icon next to the name in the **Nested Content** list. -* **Hide Label** - Enabling this will hide the property editor's label and expand the **Nested Content** property editor to the full width of the editor window. - -Once your Data Type has been configured, set-up a property on your page Document Type using your new Data Type and you are set to start editing. - -## Limitations - -There is a handful of editors that Nested Content does not support in its elements. These include: - -* [Tags](tags.md) -* [Blocklist Editor](block-editor/block-list-editor.md) -* [File upload](file-upload.md) -* [Image Cropper](image-cropper.md) - -![Editors that are not supported](../built-in-property-editors/images/NestedContent\_NotSupported.png) - -## Editing Nested Content - -When viewing a **Nested Content** editor for the first time, you'll be presented with an icon and help text to get you started. - -![Nested Content - Add Content](../built-in-property-editors/images/NestedContent\_AddContent.png) - -Click the plus icon to start creating a new item in the list. - -If your **Nested Content** editor is configured with multiple document-types you will be presented with a dialog window to select which Document Type you would like to use. - -![Nested Content - Select Schema](../built-in-property-editors/images/NestedContent\_SelectSchema-v8.png) - -Click the icon of the Document Type you wish to use and a new item will be created in the list using that Document Type. - -If you only have one Document Type configured for your **Nested Content** editor, then clicking the plus icon will not display the dialog and instead will jump straight to inserting an entry in the editor for you ready to edit. - -![Nested Content - New Item](../built-in-property-editors/images/NestedContent\_NewItem-v8.png) - -More items can be added to the list by clicking the plus icon for each additional item. - -To close the editor for an item or open the editor for another item in the list, you click the edit icon. - -![Nested Content - Edit Item](../built-in-property-editors/images/NestedContent\_EditItem-v8.png) - -To reorder the list, click and drag the move icon up and down to place the items in the order you want. - -To delete an item click the delete icon. If the minimum number of items is reached, then the delete icon will appear greyed out to prevent going below the minimum allowed number of items. - -### Single Item Mode - -If **Nested Content** is configured with a minimum and maximum item of 1, then it goes into single item mode. - -In single item mode, there is no icon displayed to add new items, and the single items editor will be open by default and its header bar removed. - -In this mode, **Nested Content** works more like a fieldset than a list editor. - -![Nested Content - Single Item Mode](../built-in-property-editors/images/NestedContent\_SingleItemMode-v8.png) - -## Rendering Nested Content - -To render the stored value of your **Nested Content** property, a built in value converter is provided for you. Call the `Value` method with a generic type of `IEnumerable` and the stored value will be returned as a list of `IPublishedElement` entities. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@{ - var items = Model.Value>("nest"); - - if (items != null) { - foreach (var item in items) - { - // Render your content, e.g. item.Value("heading") - } - } - -} -``` - -Each item is treated as a standard `IPublishedElement` entity, which means you can use all the value converters you are used to using. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using Umbraco.Cms.Core.Models.PublishedContent; -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@{ - var items = Model.Value>("nest"); - - if (items != null) { - foreach (var item in items) - { - var description = item.Value("description"); - var image = item.Value("image"); - -

@item.Value("heading")

- - if (!string.IsNullOrEmpty(description)) - { -

@description

- } - - if (image != null) - { - - } - } - } -} -``` - -### Single Item Mode - -If your **Nested Content** property editor is configured in single item mode, then the value converter will automatically know this and return a single `IPublishedElement` entity rather than an `IEnumerable` list. Therefore, when using **Nested Content** in single item mode, you can call `Value` with a generic type of `IPublishedElement` and you can start accessing the entity's properties straight away, rather than having to then fetch it from a list first. - -Example: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using Umbraco.Cms.Core.Models.PublishedContent; -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@{ - var item = Model.Value("myPropertyAlias"); - - if (item != null) { -

@item.Value("heading")

- } -} -``` - -## Creating Nested Content programmatically - -For the sake of this example, let us assume we have a Nested Content property with alias `attendeeList`, where the element Document Type has an alias of `attendee`. It has the Properties: `user_name`, `user_email`, `join_time`, `leave_time`, `duration`, `phone`. - -To save data in Nested Content, we need to create a new C# List containing a `Dictionary` of type ``. `Dictionary` would also work. The first dictionary item property/parameter we should specify for each Nested Content element is `ncContentTypeAlias`, which is the alias of the Document Type that we have nested. - -Afterwards, the entire list needs to be serialized to Json via JsonConvert. - -```csharp -@using Umbraco.Cms.Core.Models; -@using Umbraco.Cms.Core.Services; -@using Newtonsoft.Json; -@inject IContentService _contentService; - - //if the class containing our code inherits SurfaceController, UmbracoApiController, - //or UmbracoAuthorizedApiController, we can get ContentService from Services namespace - var contentService = _contentService; -//here we create a new node, and fill out attendeeList afterwards - IContent request = contentService.Create("new node", guid, "mydoctype", -1); - //our list which will contain nested content - var attendees = new List>(); -//participants is our list of attendees - multiple items, good use case for nested content - foreach (var person in participants) - attendees.Add(new Dictionary() { - //this is the only "default" value we need to fill for nested item - {"ncContentTypeAlias","attendee"}, - {"user_name", person.name}, - {"user_email",person.user_email}, - {"join_time",person.join_time.ToString()}, - //we convert some properties to String just to be on the safe side - {"leave_time",person.leave_time.ToString()}, - {"duration",person.duration.ToString()}, - {"phone",person.phone.ToString()} - }); - } - //bind the attendees List to attendeeList property on the newly created content node - request.SetValue("attendeeList", JsonConvert.SerializeObject(attendees)); - //Save the entire node via ContentService - ContentService.SaveAndPublish(request); -``` - -In the above sample we iterate through a list of participants (the data for such participants could be coming from an API, for example), and add a new `Dictionary` item for each person in the list. diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md deleted file mode 100644 index 784c6533e48..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md +++ /dev/null @@ -1,119 +0,0 @@ -# Numeric - -`Alias: Umbraco.Integer` - -`Returns: Integer` - -Numeric is an HTML input control for entering numbers. Since it's a standard HTML element the options and behaviour are all controlled by the browser and therefore is beyond the control of Umbraco. - -## Data Type Definition Example - -![Numeric Data Type Definition](../built-in-property-editors/images/numeric-datatype-v10.png) - -### Minimum - -This allows you to set up a minimum value. If you will always need a minimum value of 10 this is where you set it up and whenever you use the datatype the value will always start at 10. It's not possible to change the value to anything lower than 10. Only higher values will be accepted. - -### Step Size - -This allows you to control by how much value should be allowed to increase/decrease when clicking the up/down arrows. If you try to enter a value that does not match with the step setting then it will not be accepted. - -### Maximum - -This allows you to set up a maximum value. If you will always need a maximum value of 100 this is where you set it up. It's not possible to change the value to anything higher than 100. Only lower values will be accepted. - -## Settings - -## Content Example - -![Numeric Content Definition](../built-in-property-editors/images/numeric-content.png) - -## MVC View Examples - -### Rendering the output casting to an int (without Modelsbuilder) - -By casting the output as an int it's possible for you to do mathematical operations with the value. - -```csharp -@{ - int students = Model.HasValue("students") ? Model.Value("students") : 0; - int teachers = Model.HasValue("teachers") ? Model.Value("teachers") : 0; - int totalTravellers = students + teachers; - -

@totalTravellers

-} -``` - -### Rendering the output casting to a string (Without Modelsbuilder) - -You can also render the output by casting it to a string, which means you will not be able to do mathematical operations - -```csharp -@{ - if(Model.HasValue("students")){ -

@(Model.Value("students"))

- } -} -``` - -### With Modelsbuilder - -```csharp -@{ - int students = Model.Students; - int teachers = Model.Teachers; - int totalTravellers = students + teachers; - -

@totalTravellers

-} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'students' - content.SetValue("students", 20); - - // Save the change - contentService.Save(content); - -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'students' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.Students).Alias, 20); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md deleted file mode 100644 index 13b3cf3068d..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md +++ /dev/null @@ -1,88 +0,0 @@ -# Radiobutton List - -`Alias: Umbraco.RadioButtonList` - -`Returns: string` - -Pretty much like the name indicates this Data type enables editors to choose from list of radio buttons and returns the value of the selected item as string. - -## Data Type Definition Example - -![Radiobutton List Data Type Definition](../built-in-property-editors/images/RadioButton-List-DataType-v10.png) - -## Content Example - -![Radiobutton List Content](../built-in-property-editors/images/RadioButton-List-Content-v8.png) - -## MVC View Example - -### Typed - -#### Without Modelsbuilder - -```csharp -@if (Model.HasValue("colorTheme")) -{ - var value = Model.Value("colorTheme"); -

@value

-} -``` - -#### With Modelsbuilder - -```csharp -@if (Model.ColorTheme != null) -{ - var value = Model.ColorTheme; -

@value

-} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Set the value of the property with alias 'colorTheme' - content.SetValue("colorTheme", "water"); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'colorTheme' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.ColorTheme).Alias, "water"); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md deleted file mode 100644 index 056dc7b05f2..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Rich Text Editor - -`Alias: Umbraco.TinyMCE` - -`Returns: HTML` - -The Rich Text Editor (RTE) is based on [tinymce](https://www.tinymce.com/) and is highly configurable. Depdending on the configuration, it will give your content editors more flexibility when working with content that should be more than only plain text. - -## [Configuration options](configuration.md) - -Customize everything from toolbar options to editor size to where pasted images are saved. - -## [RTE Styles](rte-styles.md) - -Use CSS to define specific editor styles and add them to the RTE. - -## Data Type Definition Example - -![Rich Text Editor - Data Type](../../built-in-property-editors/rich-text-editor/images/rte-datatype-v10.png) - -## Content Example - -![Rich Text Editor - Content](../../built-in-property-editors/rich-text-editor/images/rte-content.png) - -## MVC View Example - -### Without Modelsbuilder - -```csharp -@{ - if (Model.HasValue("richText")){ -

@(Model.Value("richText"))

- } -} -``` - -### With Modelsbuilder - -```csharp -@{ - if (!string.IsNullOrEmpty(Model.RichText.ToString())) - { -

@Model.RichText

- } -} -``` - -## Add values programmatically - -See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](../../../../../reference/management/services/contentservice/). - -{% hint style="info" %} -The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IContentService Services; -@{ - // Get access to ContentService - var contentService = Services; - - // Create a variable for the GUID of the page you want to update - var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); - - // Get the page using the GUID you've defined - var content = contentService.GetById(guid); // ID of your page - - // Create a variable for the desired value - var htmlValue = new HtmlString("Add some text here"); - - // Set the value of the property with alias 'richText'. - content.SetValue("richText", htmlValue); - - // Save the change - contentService.Save(content); -} -``` - -Although the use of a GUID is preferable, you can also use the numeric ID to get the page: - -```csharp -@{ - // Get the page using it's id - var content = contentService.GetById(1234); -} -``` - -If Modelsbuilder is enabled you can get the alias of the desired property without using a magic string: - -```csharp -@using Umbraco.Cms.Core.PublishedCache; -@inject IPublishedSnapshotAccessor _publishedSnapshotAccessor; -@{ - // Set the value of the property with alias 'richText' - content.SetValue(Home.GetModelPropertyType(_publishedSnapshotAccessor, x => x.RichText).Alias, "Add some text here"); -} -``` diff --git a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md b/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md deleted file mode 100644 index 7b404aeb223..00000000000 --- a/10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md +++ /dev/null @@ -1,102 +0,0 @@ -# Rich Text Editor Configuration - -## Rich Text Editor Configuration - -{% embed url="https://www.youtube.com/watch?v=QRIWz9SotY4" %} -Rich Text Editor default implementation -{% endembed %} - -### Toolbar - -You have full control over which options should be available on the RTE. - -![Toolbar: All options enabled](../../built-in-property-editors/rich-text-editor/images/toolbar-all-options.png) - -In the examble above, all 34 options have been enabled. The options include copy/paste buttons, font styles like bold and italics, bullet lists and options to embed videos and insert images. - -### Stylesheets - -It is possible to define specific styles that can be used when editing content using the RTE. You can use as many of these styles with the RTE as you want. - -The RTE styles are defined in CSS files which can be created in the **Settings** section. Read the [RTE Styles](rte-styles.md) article to learn more about this feature. - -### Dimensions - -Define `height` and `width` of the editor displayed in the content section. - -### Maximum size for inserted images - -Define the maximum size for images added through the Rich Text Editor. - -If inserted images are larger than the dimensions defined here, the images will be resized automatically. - -### Mode - -The Rich Text Editor comes in two different modes: Classic and Distraction Free. - -* Classic - - The default mode, which displays the toolbar in the top. - - ![RTE Mode: Classic](../../built-in-property-editors/rich-text-editor/images/rte-mode-classic-new.png) -* Distraction Free - - In this mode the toolbar is hidden, and only shows up when content in the editor is highlighted. - - ![RTE Mode: Distraction Free](../../built-in-property-editors/rich-text-editor/images/rte-mode-distractionfree.png) - -### Overlay Size - -Select the width of the link picker overlay. The overlay size comes in three sizes: Small, Medium, and Large. - -### Hide Label - -When this option is checked the label and description for the RTE property will be hidden. - -### Ignore User Start Nodes - -Some of the backoffice users might be restricted to a specific part of the content tree. When the "Ignore User Start Nodes" is checked, the users can pick any piece of content from the content tree, when adding internal links through the RTE. - -### Image Upload Folder - -Images added through the RTE is by default added to the root of the Media library. - -Sometimes you might want to add the images to a specific folder. This folder can be configured using the "Image Upload Folder" setting. - -## Advanced Configuration - -The RTE can also accept advanced configuration through the `appSettings.json` file fed into the TinyMCE configuration. This is within `Umbraco:CMS:RichTextEditor` and allows you to configure the following: - -* [Commands](https://www.tiny.cloud/docs/advanced/editor-command-identifiers/#executablecommands) -* [Plugins](https://www.tiny.cloud/docs/configure/integration-and-setup/#plugins) -* [CustomConfig](https://www.tiny.cloud/docs/configure/integration-and-setup/) -* [ValidElements](https://www.tiny.cloud/docs/configure/content-filtering/#valid\_elements) -* [InvalidElements](https://www.tiny.cloud/docs/configure/content-filtering/#invalid\_elements) - -`CustomConfig` is slightly different from the rest as it extends the core config passed into TinyMCE. - -### Allowing script tags in the RTE - -Sometimes you want to allow your content editors to be able to add ` -``` - -![Reference the script in template](images/10-reference-script-v9.png) - -By default all JavaScript files will be stored in the `wwwroot/scripts` folder in the solution. - -{% hint style="info" %} -If you are working locally, you can create CSS and JS files outside of the Backoffice - as long as they are placed in appropriate folders (`css` and `scripts`), they will show up in the Backoffice when you right-click on the folder and then pick reload. -{% endhint %} - -## Bundling & Minification for JavaScript and CSS - -You can use whichever tool you are comfortable with for bundling & minification by implementing the `IRuntimeMinifier` interface in your custom minifier class, though it is worth noting that Umbraco 9+ ships with Smidge which offers lightweight runtime bundling and minification. - -You can create various bundles of your site's CSS or JavaScript files in your code that can be rendered later in your views. There can be a single bundle for the entire site, or a common bundle for the files you want to be loaded on every page, as well as page-specific bundles, just by listing your resources in the order you like. - -**Step 1:** Create a `INotificationHandler` - -```csharp -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.WebAssets; - -namespace Umbraco.Docs.Samples.Web.Stylesheets_Javascript -{ - public class CreateBundlesNotificationHandler : INotificationHandler - { - private readonly IRuntimeMinifier _runtimeMinifier; - private readonly IRuntimeState _runtimeState; - - public CreateBundlesNotificationHandler(IRuntimeMinifier runtimeMinifier, IRuntimeState runtimeState) { - _runtimeMinifier = runtimeMinifier; - _runtimeState = runtimeState; - } - public void Handle(UmbracoApplicationStartingNotification notification) - { - if (_runtimeState.Level == RuntimeLevel.Run) - { - _runtimeMinifier.CreateJsBundle("registered-js-bundle", - BundlingOptions.NotOptimizedAndComposite, - new[] { "~/scripts/test-script1.js", "~/scripts/test-script2.js" }); - - _runtimeMinifier.CreateCssBundle("registered-css-bundle", - BundlingOptions.NotOptimizedAndComposite, - new[] { "~/css/test-style.css" }); - } - } - } -} -``` - -{% hint style="info" %} -See below for the different [Bundling Options](stylesheets-javascript.md#bundling-options). -{% endhint %} - -**Step 2:** Register the `INotificationHandler` in the `ConfigureServices` of `Startup.cs` - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddNotificationHandler() - .Build(); -} -``` - -**Step 3:** Render the bundles by the bundle name in a view template file using the Smidge TagHelper: - -```csharp - - - - - - -``` - -### Bundling Options - -The following bundling options can be set when creating your bundles: - -```csharp -BundlingOptions.OptimizedAndComposite // The files will be minified and bundled into an individual file -BundlingOptions.OptimizedNotComposite // The files will be minified but not bundled into an individual file -BundlingOptions.NotOptimizedNotComposite // The files will not be minified and will not be bundled into an individual file -BundlingOptions.NotOptimizedAndComposite // The files will not be minified but will be bundled into an individual file -``` - -## Rendering - -### Using Smidge TagHelper - -{% hint style="info" %} -The Smidge TagHelper does not consider the value of `Umbraco:CMS:Hosting:Debug` set in your appsettings file. - -If you do need to debug bundles you can inject `hostingSettings` and add the `debug` attribute as shown below. -{% endhint %} - -```csharp -@using Microsoft.Extensions.Options -@using Umbraco.Cms.Core.Configuration.Models -@inject IOptions hostingSettings -@{ - var debugMode = hostingSettings.Value.Debug; -} -``` - -```csharp - - -``` - -### Using IRuntimeMinifier - -{% hint style="info" %} -In case you are in Debug mode, your bundles won't be minified or bundled, so you would need to set `Umbraco:CMS:Hosting:Debug: false` in your appsettings file. -{% endhint %} - -```csharp -@using Umbraco.Cms.Core.WebAssets -@inject IRuntimeMinifier runtimeMinifier - - - - @Html.Raw(await runtimeMinifier.RenderJsHereAsync("registered-js-bundle")) - @Html.Raw(await runtimeMinifier.RenderCssHereAsync("registered-css-bundle")) - - -``` - -Full details about Smidge can be found here: [https://github.com/Shazwazza/Smidge](https://github.com/Shazwazza/Smidge) diff --git a/10/umbraco-cms/fundamentals/design/templates/README.md b/10/umbraco-cms/fundamentals/design/templates/README.md deleted file mode 100644 index 7743cddcfb5..00000000000 --- a/10/umbraco-cms/fundamentals/design/templates/README.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -meta.Title: Templates in Umbraco -description: Templating in Umbraco including inheriting from master template ---- - -# Templates - -_Templating in Umbraco builds on the concept of Razor Views from ASP.NET MVC - if you already know this, then you are ready to create your first template - if not, this is a quick and handy guide._ - -## Creating your first Template - -By default, all document types should have a template attached - but in case you need an alternative template or a new one, you can create one: - -Open the **Settings** section inside the Umbraco backoffice and right-click the **Templates** folder. Choose **Create**. Enter a template name and click the **Save** button. You will now see the default template markup in the backoffice template editor. - -![Created template](images/create-template-v8.png) - -## Allowing a Template on a Document Type - -To use a template on a document, you must first allow it on the content's type. Open the Document Type you want to use the template, go to the Templates tab and select the template under the **Allowed Templates** section. - -![Allowing template](images/allow-template-v8.png) - -## Inheriting a Master Template - -A template can inherit content from a master template by using the ASP.NET views Layout feature. Let's say we have a template called **MasterView**, containing the following HTML: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@{ - Layout = null; -} - - - -

Hello world

- @RenderBody() - - -``` - -We then create a new template called **textpage** and in the template editor, click on the **Master Template** button and set its master template to the template called **MasterView**: - -![Inherit template](images/inherit-template-v8.png) - -This changes the `Layout`value in the template markup, so **textpage** looks like this: - -```csharp -@inherits Umbraco.Web.Mvc.UmbracoViewPage -@{ - Layout = "MasterView.cshtml"; -} -

My content

-``` - -When a page using the textpage template renders, the final HTML will be merged replacing the `@renderBody()` placeholder, and produce the following: - -```csharp -@inherits Umbraco.Web.Mvc.UmbracoViewPage -@{ - Layout = null; -} - - - -

Hello world

-

My content

- - -``` - -## Template Sections - -What's good to know, is that you are not limited to a single section. Template sections allow child templates that inherit the master layout template to insert HTML code up into the main layout template. For example, a child template inserting code into the `` tag of the master template. - -You can do this by using [named sections](https://www.youtube.com/watch?v=lrnJwglbGUA). Add named sections to your master template with the following code: - -```csharp -@RenderSection("SectionName") -``` - -For instance, if you want to be able to add HTML to your `` tags write: - -```csharp -@inherits Umbraco.Web.Mvc.UmbracoViewPage -@{ - Layout = null; -} - - - - Title - @RenderSection("Head") - - - - - -``` - -By default, when rendering a named section, the section is not mandatory. To make the section mandatory, add `true` or enable **Section is mandatory** field in the **Sections** option. - -```csharp -@RenderSection("Head", true) -``` - -![Create partial](images/render-named-sections-v10.png) - -On your child page template call `@section Head {}` and then type your markup that will be pushed into the Master Template: - -```csharp -@section Head { - -} -``` - -## Injecting Partial Views - -Another way to reuse HTML is to use partial views - which are small reusable views that can be injected into another view. - -Like templates, create a partial view, by right-clicking **Partial Views** and selecting **Create**. You can then either create an empty partial view or create a partial view from a snippet. - -![Create partial](images/create-partial-v8.png) - -The created partial view can now be injected into any template by using the `@Html.Partial()` method like so: - -```csharp -@inherits Umbraco.Web.Mvc.UmbracoViewPage -@{ - Layout = "MasterView.cshtml"; -} - -

My new page

-@Html.Partial("a-new-view") -``` - -### Related Articles - -* [Basic Razor syntax](basic-razor-syntax.md) -* [Rendering content](../rendering-content.md) -* [Named Sections](named-sections.md) - -### Tutorials - -* [Creating a basic website with Umbraco](../../../tutorials/creating-a-basic-website/) - -### Umbraco Learning Base - -{% embed url="https://www.youtube.com/playlist?ab_channel=UmbracoLearningBase&list=PLgX62vUaGZsFmzmm4iFKeL41CZ5YFw09z" %} -Playlist: Templates in Umbraco -{% endembed %} diff --git a/10/umbraco-cms/fundamentals/design/templates/basic-razor-syntax.md b/10/umbraco-cms/fundamentals/design/templates/basic-razor-syntax.md deleted file mode 100644 index a519ac7df6d..00000000000 --- a/10/umbraco-cms/fundamentals/design/templates/basic-razor-syntax.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -meta.Title: "Razor Syntax with Umbraco" -description: "How to perform common logical tasks in Razor like if/else, foreach loops, switch statements and using the @ character to separate code and markup" ---- - -# Basic Razor Syntax - -_Shows how to perform common logical tasks in Razor like if/else, foreach loops, switch statements and using the @ character to separate code and markup._ - -## The @ symbol - -The @ symbol is used in Razor to initiate code, and tell the compiler where to start interpreting code, instead of returning the content of the file as text. Using a single character for this separation, results in cleaner, compact code which is easier to read. - -```csharp -@* Writing a value inside a html element *@ - -

@Model.Name

- -@* Inside an attribute *@ -@Model.Name - -@* Using it to start logical structures *@ -@if (selection?.Length > 0) -{ -
    - @foreach (var item in selection) - { -
  • - @item.Name -
  • - } -
-} -``` - -## Embedding comments in razor - -Commenting your code is important, use comments to explain what the code does. `@* *@` indicates a comment, which will not be visible in the rendered output. - -```csharp -@* Here we check if the name is equal to foobar *@ -@if (Model.Name == "foobar") -{ - @foreach (var child in Model.Children) - { - @* here we write stuff for each child page *@ -

write stuff

- } -} -``` - -## If/else - -If/else statements perform one task if a condition is true, and another if the condition is not true - -```csharp -@if (Model.Name == "home") -{ -

This is the homepage!

-} - -@if (Model.NodeTypeAlias == "TextPage") -{ -

This is a textpage

-} -else -{ -

This is NOT a textpage

-} -``` - -## Foreach loops - -A foreach loop goes through a collection of items, typically a collection of pages and performs an action for each item - -```csharp -@foreach (var item in Model.Children) -{ -

The item name is: @Item.Name

-} -``` - -## Switch block - -A Switch block is used when testing a large number of conditions - -```csharp -@switch (Model.WeekDay) -{ - case "Monday": - "

It is Monday

"; - break; - case "Tuesday": - "

It is Tuesday

"; - break; - case "Wednesday": - "

It is Wednesday

"; - break; - default: - "

It's some day of the week

"; - break; -} -``` - -### More information - -- [More examples](../../../reference/templating/mvc/examples.md) -- [Querying](../../../reference/querying/README.md) diff --git a/10/umbraco-cms/fundamentals/design/templates/images/Define-named-section.png b/10/umbraco-cms/fundamentals/design/templates/images/Define-named-section.png deleted file mode 100644 index 2f2ae76a25e..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/Define-named-section.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/Render-named-sections.png b/10/umbraco-cms/fundamentals/design/templates/images/Render-named-sections.png deleted file mode 100644 index 07bfb69de7d..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/Render-named-sections.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/Sections-option.png b/10/umbraco-cms/fundamentals/design/templates/images/Sections-option.png deleted file mode 100644 index cbff077027e..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/Sections-option.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/allow-template-v8.png b/10/umbraco-cms/fundamentals/design/templates/images/allow-template-v8.png deleted file mode 100644 index a18945a38da..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/allow-template-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/allow-template.png b/10/umbraco-cms/fundamentals/design/templates/images/allow-template.png deleted file mode 100644 index 779d2e9405a..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/allow-template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/create-partial-v8.png b/10/umbraco-cms/fundamentals/design/templates/images/create-partial-v8.png deleted file mode 100644 index 3f51d809f52..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/create-partial-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/create-partial.png b/10/umbraco-cms/fundamentals/design/templates/images/create-partial.png deleted file mode 100644 index cebe05214a2..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/create-partial.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/create-template-v8.png b/10/umbraco-cms/fundamentals/design/templates/images/create-template-v8.png deleted file mode 100644 index 47fa57416a0..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/create-template-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/create-template.png b/10/umbraco-cms/fundamentals/design/templates/images/create-template.png deleted file mode 100644 index cb5fa5dfe79..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/create-template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/inherit-template-v8.png b/10/umbraco-cms/fundamentals/design/templates/images/inherit-template-v8.png deleted file mode 100644 index cdefa5b56bf..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/inherit-template-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/inherit-template.png b/10/umbraco-cms/fundamentals/design/templates/images/inherit-template.png deleted file mode 100644 index 8b6ae7749b8..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/inherit-template.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/render-named-sections-v10.png b/10/umbraco-cms/fundamentals/design/templates/images/render-named-sections-v10.png deleted file mode 100644 index 6cbeb2a8072..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/render-named-sections-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/template-sections-v8.png b/10/umbraco-cms/fundamentals/design/templates/images/template-sections-v8.png deleted file mode 100644 index d8ce4c1268e..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/template-sections-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/images/template-sections.png b/10/umbraco-cms/fundamentals/design/templates/images/template-sections.png deleted file mode 100644 index d8ce4c1268e..00000000000 Binary files a/10/umbraco-cms/fundamentals/design/templates/images/template-sections.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/design/templates/named-sections.md b/10/umbraco-cms/fundamentals/design/templates/named-sections.md deleted file mode 100644 index f152e4c8e3b..00000000000 --- a/10/umbraco-cms/fundamentals/design/templates/named-sections.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -meta.Title: Named Sections in Umbraco -description: Using named sections in Umbraco ---- - -# Named Sections - -Template sections support the ability to add additional _Named Sections_ to layout templates. These sections can be defined anywhere in the layout file (including within the section of the HTML) and allow you to output dynamic content in your template. - -## Defining a Named Section - -You can define a part of your template as a named section by wrapping it in `@section`. This can be rendered in a specific area of the parent of this template, by using `@RenderSection`. - -For example, you can define the following section within a child template like a Content page: - -```csharp -@section Contact -{ -
-
-
-

@Model.AuthorName()

-
-
-
- -} -``` - -To define a Named Section, follow these steps: - -1. Go to **Settings**. -2. Navigate to a template and click **Sections**. - -
-3. Select **Define a named section** and enter the **Section Name**. ![Define Named Sections Menu](images/Define-named-section.png) -4. Click **Submit**. - -## Render a Name Section - -Renders a named area of a child template, by inserting a `@RenderSection(name)` placeholder. This renders an area of a child template that is wrapped in a corresponding `@section [name]` definition. - -For example, you can define the following section within a Master template: - -```csharp -@RenderSection("Contact", false) -``` - -To render a Named Section, follow these steps: - -1. Go to **Settings**. -2. Navigate to a template and click **Sections**. - -
-3. Select **Render a named section** and enter the **Section Name**. ![Render Named Sections Menu](images/Render-named-sections.png) -4. \[Optional] Select **Section is mandatory**. This means that the child templates need to have the named section defined for them to work. -5. Click **Submit**. diff --git a/10/umbraco-cms/fundamentals/design/templates/razor-cheatsheet.md b/10/umbraco-cms/fundamentals/design/templates/razor-cheatsheet.md deleted file mode 100644 index a1232f321cb..00000000000 --- a/10/umbraco-cms/fundamentals/design/templates/razor-cheatsheet.md +++ /dev/null @@ -1,2 +0,0 @@ -# Razor Cheatsheet - diff --git a/10/umbraco-cms/fundamentals/get-to-know-umbraco.md b/10/umbraco-cms/fundamentals/get-to-know-umbraco.md deleted file mode 100644 index f24a8db91ab..00000000000 --- a/10/umbraco-cms/fundamentals/get-to-know-umbraco.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -description: >- - All the fundamentals of using Umbraco - from making a local installation to - extending the backend. ---- - -# Get to know Umbraco - -In this part of the Umbraco CMS documentation, you can get to know the product and the default functionality. It is here you start your Umbraco journey with the installation, setup, and basics of working with the CMS. - -
SetupFind requirements for both local development and hosting as well as guides for installing and upgrading Umbraco CMS.setupsetup-image.png
BackofficeLearn about the different sections found in the Umbraco CMS backoffice and get an overview of the available features.backofficesetup.png
DataDive a little deeper and learn how to create different types of data directly from the Umbraco CMS backoffice.datadata.png
DesignGet to know the different options the Umbraco CMS backoffice provides for designing your website.designdesign.png
CodeA high-level overview of working with some of the more advanced elements like services and notifications.codecode-image.png
diff --git a/10/umbraco-cms/fundamentals/setup/README.md b/10/umbraco-cms/fundamentals/setup/README.md deleted file mode 100644 index ba58139033d..00000000000 --- a/10/umbraco-cms/fundamentals/setup/README.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -meta.Title: "How to install and configure your Umbraco installation" -description: "Information on the requirements to setup, install & upgrade Umbraco" ---- - -# Setup - -How to install and configure your Umbraco installation. - -## [Requirements](requirements.md) - -Defines the system requirements to run Umbraco. - -## [Install](install/README.md) - -Umbraco installation steps and guidelines. - -## [Upgrading](upgrading/README.md) - -Covers the steps to upgrade your copy of Umbraco to a newer version. - -## [Server Setup](server-setup/README.md) - -Information about server setup for Umbraco including information about permissions and load balancing. - -## [Config](../../reference/configuration/README.md) - -How to configure your Umbraco installation. Includes information about all of Umbraco's configuration files and options. - -## [Installing the latest nightly builds](install/installing-nightly-builds.md) - -How to install the latest nightly builds. diff --git a/10/umbraco-cms/fundamentals/setup/install/README.md b/10/umbraco-cms/fundamentals/setup/install/README.md deleted file mode 100644 index a1c86aa7523..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/README.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -description: Instructions on installing Umbraco on various platforms using various tools. ---- - -# Installation - -## Install Umbraco using CLI - -The fastest way to get the latest version of Umbraco up and running is using the command line (CLI). - -1. Open your command line. -2. Install the Umbraco templates: - -```bash -dotnet new install Umbraco.Templates::10.* -``` - -{% hint style="info" %} - -Replace `10.*` with the specific version you want to install. - -Example: - -```bash -dotnet new install Umbraco.Templates::10.8.10 -``` - -3. Create a new project: - -```bash -dotnet new umbraco --name MyProject -``` - -4. Navigate to the newly created project folder. It will be the folder containing the `.csproj` file: - -```bash -cd MyProject -``` - -5. Build and run the newly created Umbraco site: - -```bash -dotnet run -``` - -6. The console will output a message similar to: `[10:57:39 INF] Now listening on: https://localhost:44388` -7. Open your browser and navigate to that URL. -8. Follow the instructions to finish up the installation of Umbraco. - -{% hint style="info" %} -Members of the Umbraco Community have created a website that makes the installation of Umbraco a lot easier for you. You can find the website at [https://psw.codeshare.co.uk](https://psw.codeshare.co.uk). On the website, you can configure your options to generate the required script to run. Click on the Install Script tab to get the commands you need to paste into the terminal. This tab also includes the commands for adding a starter kit or unattended install which creates the database for you. -{% endhint %} - -## Alternative Methods for Installing Umbraco - -There are numerous ways to install Umbraco. Below, you can find links to different installation methods that will help you easily install and set up Umbraco projects. - -### [.NET CLI installation](install-umbraco-with-templates.md) - -.NET CLI, included with the .NET Software Development Kit (SDK), can be used to install or uninstall .NET templates from NuGet. This can be done by using the `dotnet new` command on any OS. The underlying Template Engine enables the creation of custom templates which make new project bootstrapping much faster. With a few steps you can have an Umbraco project running without the need for a code editor. - -### [Visual Studio installation](visual-studio.md) - -Visual Studio is used to write native code and managed code supported by .NET and many others. Its built-in tools provide the ability to develop and execute applications for any platform. Developers will be able to install Umbraco without ever having to leave Visual Studio. - -### [Run Umbraco on IIS](iis.md) - -Learn how to run an already installed local installation of Umbraco. - -### [VS Code installation](install-umbraco-with-vs-code.md) - -Visual Studio Code is an editor with an embedded webserver (through the IIS Express extension). A fast way to get you up and running with Umbraco. - -### [Installing Nightly Builds](installing-nightly-builds.md) - -From Umbraco v9 and above you can use the Nightly Builds to get the latest version to use and test before it is released. Learn how to install the Nightly builds to get started. - -### [Running Umbraco on Linux/macOS](running-umbraco-on-linux-macos.md) - -Since Umbraco 9 it has been possible to run Umbraco CMS natively on Linux or macOS High Sierra. To get Umbraco running you will need to follow some steps. - -### [Install Umbraco unattended](unattended-install.md) - -Use the Unattended installs when spinning up Umbraco instances on something like Azure Web Apps to avoid having to run through the installation wizard. diff --git a/10/umbraco-cms/fundamentals/setup/install/iis.md b/10/umbraco-cms/fundamentals/setup/install/iis.md deleted file mode 100644 index 2aff4f992fa..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/iis.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -meta.Title: Local IIS with Umbraco 9 -description: This article describes how to run an Umbraco 9 site on a local IIS server. ---- - -# Local IIS With Umbraco - -This is a quick guide on getting your Umbraco website running locally on IIS. - -The guide will assume you already have IIS configured and know your way around it, as well as having a local website you wish to host. - -## Setting up prerequisites - -First, you need to ensure you have "Development time IIS support installed". To check this, go to the Visual Studio installer, click modify and check on the right side under "ASP.NET and web development": - -![Checking the IIS module exists](../../../../../13/umbraco-cms/fundamentals/setup/install/images/iis-module.png) - -Once that is installed you should set up a new IIS site - and make sure to add the hostname to your hosts file as well. Here is my setup for an example: - -![IIS site example](../../../../../13/umbraco-cms/fundamentals/setup/install/images/iis-site.png) - -{% hint style="info" %} -For the path you want to point it at the root of your site - where the `.csproj` file is. -{% endhint %} - -## Add permissions to NuGet cache folder - -You might need to change permissions for the NuGet cache folder - `C:\users\\.nuget\packages`. The user or group (IIS\_IUSRS) that the IIS site is running on requires Read permissions on this folder because this is where some of the files for Umbraco and Umbraco packages are being served from during development. If the IIS user or group does not have permission to read from the NuGet cache folder, you could run into a `DirectoryNotFoundException` while running the site. - -When the site is published these files are copied from the NuGet cache folder to `wwwroot/umbraco` and `wwwroot/App_Plugins` and these folders will typically have the correct permissions. For more information on setting permissions, see the [File and folder permissions](../server-setup/permissions.md) article. - -## Add new launch profile - -At this point you can go to your Visual Studio solution of the site and in the `Properties` folder there is a `launchSettings.json` file, that looks like this: - -```json -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:40264", - "sslPort": 44360 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Umbraco.Web.UI.NetCore": { - "commandName": "Project", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:44360;http://localhost:40264" - } - } -} -``` - -You can add a new profile called IIS, and point it at your local domain. Here it is with my example domain: - -```json -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iis": { - "applicationUrl": "https://testsite.local", - "sslPort": 0 - }, - "iisExpress": { - "applicationUrl": "http://localhost:40264", - "sslPort": 44360 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "IIS": { - "commandName": "IIS", - "launchBrowser": true, - "launchUrl": "https://testsite.local", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Umbraco.Web.UI.NetCore": { - "commandName": "Project", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:44360;http://localhost:40264" - } - } -} -``` - -At this point IIS will be added to the launch profiles, and you can run the site from Visual Studio by choosing IIS in the dropdown: - -![Launch profiles](../../../../../13/umbraco-cms/fundamentals/setup/install/images/launchprofiles.png) - -And finally the site is running from your local IIS: - -![Local IIS site](../../../../../13/umbraco-cms/fundamentals/setup/install/images/voila.png) diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204006.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204006.png deleted file mode 100644 index 1d3c945c2a9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204006.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204144.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204144.png deleted file mode 100644 index c7c600948b3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204144.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204429.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204429.png deleted file mode 100644 index 52dbb612873..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204429.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204433.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204433.png deleted file mode 100644 index efe194d3e53..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_204433.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_223022.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_223022.png deleted file mode 100644 index b7dceace3c4..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-12_223022.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-17_164508.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-17_164508.png deleted file mode 100644 index a1e8f9856b9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-17_164508.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-17_173822.png b/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-17_173822.png deleted file mode 100644 index 78b3a4db373..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Manual/2012-03-17_173822.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Latest_nightly_build_version.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Latest_nightly_build_version.jpg deleted file mode 100644 index 341da76534c..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Latest_nightly_build_version.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Manage_NuGet_Pkgs.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Manage_NuGet_Pkgs.jpg deleted file mode 100644 index 68138f7e4b6..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Manage_NuGet_Pkgs.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Manage_Packages.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Manage_Packages.jpg deleted file mode 100644 index 9ff2c8538dc..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Manage_Packages.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/NewFeed_Details.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/NewFeed_Details.jpg deleted file mode 100644 index 5ce96af75da..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/NewFeed_Details.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/NuGet_NewFeed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/NuGet_NewFeed.jpg deleted file mode 100644 index e17dee522b9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/NuGet_NewFeed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Register_Nightly_Feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Register_Nightly_Feed.jpg deleted file mode 100644 index bd549030ecc..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Register_Nightly_Feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Rider_Nightly_Feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Rider_Nightly_Feed.jpg deleted file mode 100644 index 68701876301..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Rider_Nightly_Feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Rider_Nightly_Feed_version.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Rider_Nightly_Feed_version.jpg deleted file mode 100644 index 9b60bb59f21..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Nightly/Rider_Nightly_Feed_version.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/enable-package-manager-console-v8.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/enable-package-manager-console-v8.png deleted file mode 100644 index 9b0a1ade255..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/enable-package-manager-console-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/enable-package-manager-console.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/enable-package-manager-console.png deleted file mode 100644 index b04913257fe..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/enable-package-manager-console.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/manage-nuget-packages-v8.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/manage-nuget-packages-v8.png deleted file mode 100644 index 7cb2bc648ed..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/manage-nuget-packages-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/manage-nuget-packages.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/manage-nuget-packages.png deleted file mode 100644 index 758cdb3f246..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/manage-nuget-packages.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-dotnet4.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-dotnet4.png deleted file mode 100644 index 18cc5e95e3c..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-dotnet4.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2012.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2012.png deleted file mode 100644 index 8278146c95b..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2012.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-1.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-1.png deleted file mode 100644 index e336c5e672c..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-2.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-2.png deleted file mode 100644 index 166878fd19c..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-2.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-3.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-3.png deleted file mode 100644 index 0a9ccb0e8f4..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2013-3.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2017-1-v8.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2017-1-v8.png deleted file mode 100644 index e745a23ac68..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2017-1-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2017-2-v8.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2017-2-v8.png deleted file mode 100644 index 0129e11fa81..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/new-project-vs2017-2-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog (1) (1).png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog (1) (1).png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog (1).png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog (1).png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog.png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-overwrite-dialog.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-search-v8.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-search-v8.png deleted file mode 100644 index e0edef36004..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-search-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-search.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-search.png deleted file mode 100644 index 71dd8c30c5d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-search.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-update.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-update.png deleted file mode 100644 index 1a50a023a0c..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/nuget-update.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/package-manager-console-overwrite.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/package-manager-console-overwrite.png deleted file mode 100644 index 267d5c0e5d1..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/package-manager-console-overwrite.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/package-manager-console.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/package-manager-console.png deleted file mode 100644 index 2a2b89de938..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/package-manager-console.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/visual-studio-version-v8.png b/10/umbraco-cms/fundamentals/setup/install/images/NuGet/visual-studio-version-v8.png deleted file mode 100644 index efba7ce0289..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/NuGet/visual-studio-version-v8.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Rider/add-the-feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Rider/add-the-feed.jpg deleted file mode 100644 index 818aea631f8..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Rider/add-the-feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Rider/choose-the-feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Rider/choose-the-feed.jpg deleted file mode 100644 index 03ad0197afe..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Rider/choose-the-feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Rider/find-the-version.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Rider/find-the-version.jpg deleted file mode 100644 index a9a7e2aba07..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Rider/find-the-version.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/Rider/open-add-feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/Rider/open-add-feed.jpg deleted file mode 100644 index 9212394b306..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/Rider/open-add-feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/Umbraco10_install.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/Umbraco10_install.png deleted file mode 100644 index b1005b76548..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/Umbraco10_install.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/additional-info.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/additional-info.png deleted file mode 100644 index 9429fc52c81..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/additional-info.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/configure-project.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/configure-project.png deleted file mode 100644 index b5882efaab7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/configure-project.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/create-project.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/create-project.png deleted file mode 100644 index a75a86267b1..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/create-project.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/find-the-version.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VS/find-the-version.jpg deleted file mode 100644 index 7e82fe6ee2b..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/find-the-version.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/open-nuget-package-manager.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VS/open-nuget-package-manager.jpg deleted file mode 100644 index b671b595c7a..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/open-nuget-package-manager.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/open-nuget-setttings.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VS/open-nuget-setttings.jpg deleted file mode 100644 index bf51a558012..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/open-nuget-setttings.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/ready-solution.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/ready-solution.png deleted file mode 100644 index 9059c79ec2f..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/ready-solution.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/registering-nightly-feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VS/registering-nightly-feed.jpg deleted file mode 100644 index 468f63a7e1e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/registering-nightly-feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/select-nuget-feed.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VS/select-nuget-feed.jpg deleted file mode 100644 index 2479463ebbd..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/select-nuget-feed.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/visual-studio-version-v10.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/visual-studio-version-v10.png deleted file mode 100644 index 16638b8c2a9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/visual-studio-version-v10.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VS/visual-studio-version-v9.png b/10/umbraco-cms/fundamentals/setup/install/images/VS/visual-studio-version-v9.png deleted file mode 100644 index e7aea38b466..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VS/visual-studio-version-v9.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/1.PNG b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/1.PNG deleted file mode 100644 index f279c232dde..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/1.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/2.PNG b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/2.PNG deleted file mode 100644 index cb5d150d76a..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/2.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/3.PNG b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/3.PNG deleted file mode 100644 index e5759f35f58..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/3.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/4.PNG b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/4.PNG deleted file mode 100644 index 364fe1c4a3f..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/4.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Additional_Info.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Additional_Info.jpg deleted file mode 100644 index 72a2929b890..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Additional_Info.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/ConfigureTask.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/ConfigureTask.png deleted file mode 100644 index 880a0e3e594..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/ConfigureTask.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Create_LaunchJson_file.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Create_LaunchJson_file.jpg deleted file mode 100644 index 0ce06b712d2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Create_LaunchJson_file.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Dropdown_option.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Dropdown_option.jpg deleted file mode 100644 index 8c6c135c273..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Dropdown_option.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Install_Umbraco.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Install_Umbraco.jpg deleted file mode 100644 index 88c43ab285e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Install_Umbraco.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Installer-v8.PNG b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Installer-v8.PNG deleted file mode 100644 index 3b9d2a263a6..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Installer-v8.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Installer-v9.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Installer-v9.png deleted file mode 100644 index 30036fadebb..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Installer-v9.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Marketplace.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Marketplace.jpg deleted file mode 100644 index e9d31ab959e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Marketplace.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTask.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTask.png deleted file mode 100644 index 41d2f75c4b4..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTask.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTemplate.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTemplate.png deleted file mode 100644 index f8f28bc4d02..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTemplate.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/New_Project.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/New_Project.jpg deleted file mode 100644 index 0666959592a..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/New_Project.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Prompt_Menu.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Prompt_Menu.jpg deleted file mode 100644 index e700d4609b9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Prompt_Menu.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Solution_Explorer.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Solution_Explorer.png deleted file mode 100644 index 254eb8d89be..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/Solution_Explorer.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/TaskJsonFromTemplate.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/TaskJsonFromTemplate.png deleted file mode 100644 index 8c11cb849b1..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/TaskJsonFromTemplate.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/VS_Code_Explorer.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/VS_Code_Explorer.png deleted file mode 100644 index 8a2fb9da115..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/VS_Code_Explorer.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/VsCodeExtension.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/VsCodeExtension.png deleted file mode 100644 index 8cdb2030c56..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/VsCodeExtension.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/creatingLaunchFile.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/creatingLaunchFile.png deleted file mode 100644 index 3f4d7881f43..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/creatingLaunchFile.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/dashboard-v8.PNG b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/dashboard-v8.PNG deleted file mode 100644 index 1855ef73dac..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/dashboard-v8.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/launchJson.jpg b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/launchJson.jpg deleted file mode 100644 index a9a8171036e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/launchJson.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/netcoreStructure.png b/10/umbraco-cms/fundamentals/setup/install/images/VsCode/netcoreStructure.png deleted file mode 100644 index 2080f1f70a9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/VsCode/netcoreStructure.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-db-CE.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-db-CE.png deleted file mode 100644 index b0554e526b1..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-db-CE.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-db-install.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-db-install.png deleted file mode 100644 index f19b1d36b03..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-db-install.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-finish.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-finish.png deleted file mode 100644 index e2d51d1801b..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-finish.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-start.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-start.png deleted file mode 100644 index e16b4d6e776..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-start.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-starter-kit.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-starter-kit.png deleted file mode 100644 index a3cea2b6991..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-starter-kit.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-user.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-user.png deleted file mode 100644 index a92f5250986..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/web-user.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-license.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-license.png deleted file mode 100644 index 49dffdfbe4e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-license.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-search.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-search.png deleted file mode 100644 index 97d50abf896..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-search.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-start.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-start.png deleted file mode 100644 index 5e2c73592d5..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix-start.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-database.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-database.png deleted file mode 100644 index 62b51b346e9..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-database.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-install-complete.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-install-complete.png deleted file mode 100644 index 6d11719b8be..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-install-complete.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-localhost.png b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-localhost.png deleted file mode 100644 index 0f913f58c8a..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-localhost.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-start.PNG b/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-start.PNG deleted file mode 100644 index 9c11306027f..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebMatrix/webmatrix3-start.PNG and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/add-from-gallery.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/add-from-gallery.png deleted file mode 100644 index eeadc0a3d48..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/add-from-gallery.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/complete.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/complete.png deleted file mode 100644 index 71b4bb4bbbd..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/complete.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-step1.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-step1.png deleted file mode 100644 index 1c01b42223b..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-step1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-step2.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-step2.png deleted file mode 100644 index 19fe74b991d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-step2.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-type.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-type.png deleted file mode 100644 index 44f2d5eabf8..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/db-type.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/download-files.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/download-files.png deleted file mode 100644 index 680395ed6f7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/download-files.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/search-umbraco.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/search-umbraco.png deleted file mode 100644 index e24d4ab579e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/search-umbraco.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/warning.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/warning.png deleted file mode 100644 index 72f22d11b5d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/warning.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-db.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-db.png deleted file mode 100644 index be216c66262..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-db.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-done.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-done.png deleted file mode 100644 index 5df0672bfca..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-done.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-install.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-install.png deleted file mode 100644 index 170c569fb26..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-install.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-start.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-start.png deleted file mode 100644 index 3326f300736..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-start.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-starter.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-starter.png deleted file mode 100644 index a32e55d9d4d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-starter.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-user.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-user.png deleted file mode 100644 index 16e19cf1d93..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/web-user.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/website.png b/10/umbraco-cms/fundamentals/setup/install/images/WebPl/website.png deleted file mode 100644 index b578ff608be..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/WebPl/website.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/iis-module.png b/10/umbraco-cms/fundamentals/setup/install/images/iis-module.png deleted file mode 100644 index b139dcb4804..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/iis-module.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/iis-site.png b/10/umbraco-cms/fundamentals/setup/install/images/iis-site.png deleted file mode 100644 index dd07e16fb94..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/iis-site.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/installer.png b/10/umbraco-cms/fundamentals/setup/install/images/installer.png deleted file mode 100644 index 2c109064317..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/installer.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/launchprofiles.png b/10/umbraco-cms/fundamentals/setup/install/images/launchprofiles.png deleted file mode 100644 index 7cc99dd19c5..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/launchprofiles.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/unattended/VS-unattended-install.png b/10/umbraco-cms/fundamentals/setup/install/images/unattended/VS-unattended-install.png deleted file mode 100644 index 058af6bad78..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/unattended/VS-unattended-install.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/unattended/final-screen.png b/10/umbraco-cms/fundamentals/setup/install/images/unattended/final-screen.png deleted file mode 100644 index f20cd2a606e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/unattended/final-screen.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/images/voila.png b/10/umbraco-cms/fundamentals/setup/install/images/voila.png deleted file mode 100644 index 1b094bdb556..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/install/images/voila.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/install/install-umbraco-with-templates.md b/10/umbraco-cms/fundamentals/setup/install/install-umbraco-with-templates.md deleted file mode 100644 index c5ade65bedc..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/install-umbraco-with-templates.md +++ /dev/null @@ -1,177 +0,0 @@ -# Install using .NET CLI - -We have made custom Umbraco templates that are available for use with `dotnet new`. The steps below will demonstrate the minimum amount of actions required to get you going and set up an Umbraco project from the command line using .NET templates. - -## Video Tutorial - -{% embed url="https://www.youtube-nocookie.com/embed/ZByL3qILNnI" %} -Video tutorial -{% endembed %} - -## Install the template - -1. Install the latest [.NET SDK](https://dotnet.microsoft.com/download). -2. Run `dotnet new install Umbraco.Templates` to install the project templates.\ - &#xNAN;_The solution is packaged up into the NuGet package_ [_Umbraco.Templates_](https://www.nuget.org/packages/Umbraco.Templates) _and can be installed into the dotnet CLI_. - -> Once that is complete, you can see that Umbraco was added to the list of available projects types by running `dotnet new --list`: - -{% tabs %} -{% tab title="Latest version" %} -```none -Templates Short Name Language Tags ------------------------------------------------------------------------------------------------------- -Umbraco Project umbraco [C#] Web/CMS/Umbraco -Umbraco Package umbracopackage [C#] Web/CMS/Umbraco/Package/Plugin -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```none -Templates Short Name Language Tags ------------------------------------------------------------------------------------------------------- -Umbraco Solution umbraco [C#] Web/CMS/Umbraco -Umbraco Package umbracopackage [C#] Web/CMS/Umbraco/Package/Plugin -``` -{% endtab %} -{% endtabs %} - -{% hint style="info" %} -In some cases the templates may silently fail to install (usually this is an issue with NuGet sources). If this occurs you can try specifying the NuGet source in the command by running `dotnet new install Umbraco.Templates --nuget-source "https://api.nuget.org/v3/index.json"`. -{% endhint %} - -To get **help** on a project template with `dotnet new` run the following command: - -`dotnet new umbraco -h` - -From that command's output, you will get a better understanding of what are the default template options, as well as those command-line flags specific to Umbraco that you can use (as seen below): - -{% tabs %} -{% tab title="Latest version" %} -```none -Umbraco Project (C#) -Author: Umbraco HQ -Description: An empty Umbraco project ready to get started. -Options: - -v|--version The version of Umbraco.Cms to add as PackageReference. - string - Optional - Default: 10.0.0 - - --use-https-redirect Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting. - bool - Optional - Default: false - - --no-restore If specified, skips the automatic restore of the project on create. - bool - Optional - Default: false - - --exclude-gitignore Whether to exclude .gitignore from the generated template. - bool - Optional - Default: false - - --minimal-gitignore Whether to only include minimal (Umbraco specific) rules in the .gitignore. - bool - Optional - Default: false - - --connection-string Database connection string used by Umbraco. - string - Optional - - --connection-string-provider-name Database connection string provider name used by Umbraco. - string - Optional - Default: Microsoft.Data.SqlClient - - --development-database-type Database type used by Umbraco for development. - None - Do not configure a database for development. - SQLite - Use embedded SQLite database. - LocalDB - Use embedded LocalDB database (requires SQL Server Express with Advanced Services). - Default: None - - --friendly-name Used to specify the name of the default admin user when using unattended install on development (stored as plain text). - string - Optional - - --email Used to specify the email of the default admin user when using unattended install on development (stored as plain text). - string - Optional - - --password Used to specify the password of the default admin user when using unattended install on development (stored as plain text). - string - Optional - - --no-nodes-view-path Path to a custom view presented with the Umbraco installation contains no published content. - string - Optional - - -p|--PackageTestSiteName The name of the package project this should be a test site for. - string - Optional -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```none -Umbraco Project (C#) -Author: Umbraco HQ -Description: An empty Umbraco Project ready to get started -Options: - -v|--version The version of Umbraco to load using NuGet - string - Optional - Default: 9.0.0 - - -p|--PackageTestSiteName The name of the package this should be a test site for (Default: '') - text - Optional - - -ce|--SqlCe Adds the required dependencies to use SqlCE (Windows only) (Default: false) - bool - Optional - Default: false - - -F|--Framework The target framework for the project - net5.0 - Target net5.0 - net6.0 - Target net6.0 - Default: net5.0 - - --no-restore If specified, skips the automatic restore of the project on create - bool - Optional - Default: false - - --friendly-name The friendly name of the user for Umbraco login when using Unattended install (Without installer wizard UI) - text - Optional - - --email Email to use for Umbraco login when using Unattended install (Without installer wizard UI) - text - Optional - - --password Password to use for Umbraco login when using Unattended install (Without installer wizard UI) - text - Optional - - --connection-string Database connection string when using Unattended install (Without installer wizard UI) - text - Optional - - --no-nodes-view-path Path to a custom view presented with the Umbraco installation contains no published content - text - Optional - - --use-https-redirect Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting (Default: false) - bool - Optional - Default: false -``` -{% endtab %} -{% endtabs %} - -## Create an Umbraco project - -1. Create a new empty Umbraco solution using MS SQL Azure/Server:\ - `dotnet new umbraco -n MyCustomUmbracoProject` - -You will now have a new project with the name _MyCustomUmbracoProject_, or the name you chose to use. The new project can be opened and run using your favorite IDE or you can continue using the CLI commands. - -{% hint style="info" %} -If you want to create a solution file as well you can run the commands below.\ -`dotnet new sln`\ -`dotnet sln add MyCustomUmbracoProject` -{% endhint %} - -## Run Umbraco - -1. Navigate to the newly created project folder:\ - `cd MyCustomUmbracoProject` -2. Build and run the new Umbraco .Net Core project:\ - `dotnet build`\ - `dotnet run` - -The project is now running on the [Kestrel server](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/?view=aspnetcore-5.0\&tabs=windows#kestrel) and has assigned a free available port to run it on. Look in the terminal window after the `dotnet run` command to see the URLs. - -The next step is to run through the Umbraco CMS installation. If you chose to use MS SQL Server/Azure you will need to add your connection string during this setup process to get access to the Umbraco backoffice. diff --git a/10/umbraco-cms/fundamentals/setup/install/install-umbraco-with-vs-code.md b/10/umbraco-cms/fundamentals/setup/install/install-umbraco-with-vs-code.md deleted file mode 100644 index 2eaa0ff94a6..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/install-umbraco-with-vs-code.md +++ /dev/null @@ -1,80 +0,0 @@ -# Install Umbraco With Visual Studio Code - -Follow these steps to set up an Umbraco project with VS Code. The benefit of using VS Code is that it is super quick to get up and running. - -## Installing and setting up VS Code - -1. Go to [https://code.visualstudio.com/](https://code.visualstudio.com/) and download VS Code for free. -2. Once installed, launch VS Code. -3. Click the extensions menu at the bottom on the left side. Then search for **C#**, install it then press reload. - - ![VS Code install extension](images/VsCode/Marketplace.jpg) - -## Creating your Umbraco project - -Follow the [Templates Guide](install-umbraco-with-templates.md) to create your project folder. - -## Configure VS Code to run the Umbraco project - -Open your project folder in VS Code, your project will look something like this: - -![Fresh Umbraco installation](images/VsCode/VS_Code_Explorer.png) - -Now we need to tell VS Code how to run your project. - -Open the command palette, you can use the shortcut `Ctrl+Shift+P`, and type in `Tasks: Configure` and select the `Tasks: Configure Task` option: - -![Configure task option](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VsCode/ConfigureTask.png) - -Select "Create task.json from template" - -![Create task from template](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VsCode/TaskJsonFromTemplate.png) - -Now select ".NET Core" as your template. - -![Create .NET Core Template](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VsCode/NetcoreTemplate.png) - -After this VS Code will have created a folder called `.vscode` that contains a file called `tasks.json`, it's this file that tells VS Code how to build your project. - -Now that we've told VS Code how to build your project, we need to tell it how to launch it. VS Code can do this for you. First, select the little play button in the left side menu, and then select the "create a launch.json file" link. - -![Creating launch.json file](images/VsCode/Create_LaunchJson_file.jpg) - -This will prompt a menu to appear, select **.NET 5+ and .NET Core**: - -![Prompt Menu](images/VsCode/Prompt_Menu.jpg) - -{% hint style="info" %} -If **.NET 5+ and .NET Core** is missing in the drop-down menu: - -1. Press **Ctrl + Shift + P** (on Windows/Linux) or **Cmd + Shift + P** (on macOS) to open the Command Palette. -2. Search for the command `.NET: Generate Assets for Build and Debug`. This command will generate the necessary assets for building and debugging your .NET application. -{% endhint %} - -Now you'll see a green play button appear with a dropdown where ".NET Core Launch" is selected. - -![Green play button options](images/VsCode/Dropdown_option.jpg) - -If you navigate to the Files section, a new `launch.json` file is created in the `.vscode` folder. When you press F5, the `launch.json` file tells VS Code to build your project, run it, and then open a browser . - -![launch.json file](images/VsCode/launchJson.jpg) - -With that, you're ready to run the project! Press F5, or click the little green play button in the **Run and Debug** section to run your brand new Umbraco site locally. - -## Umbraco Web Installer - -This section continues from where we left off but covers the installation and configuration of Umbraco inside your web browser when you run Umbraco for the first time. - -You will see the install screen where you will need to fill in some data before Umbraco can be installed. - -![Web Installer - Lets Get Started](images/VsCode/Install_Umbraco.jpg) - -When the installer is done you will automatically be logged into the backoffice. - -
- -Congratulations, you have installed an Umbraco site! - -{% hint style="info" %} -You can log into your Umbraco site by entering the following into your browser: http://yoursite.com/umbraco/. -{% endhint %} diff --git a/10/umbraco-cms/fundamentals/setup/install/installing-nightly-builds.md b/10/umbraco-cms/fundamentals/setup/install/installing-nightly-builds.md deleted file mode 100644 index 62323ec6665..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/installing-nightly-builds.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -meta.Title: Installing Umbraco Nightly Builds -description: Instructions on installing nightly builds of Umbraco. ---- - -# Installing Nightly Builds - -In this article, we'll explain how you can get the latest builds of Umbraco. You can do this in three steps: - -1. [Adding the nightly feed as a NuGet source](installing-nightly-builds.md#adding-the-nightly-feed-as-a-nuget-source) -2. [Finding the latest nightly version](installing-nightly-builds.md#finding-the-latest-nightly-version) -3. [Installing the latest nightly version template](installing-nightly-builds.md#installing-the-latest-nightly-version-template) - -## Adding the nightly feed as a NuGet source - -The NuGet feed containing the nightly builds is `https://www.myget.org/F/umbraconightly/api/v3/index.json`. - -You can either add this feed through the command line or use an IDE of your choice. In this article, we'll provide steps for: - -* [Using the command line](installing-nightly-builds.md#option-1-using-the-command-line) -* [Using Visual Studio](installing-nightly-builds.md#option-2-using-visual-studio) -* [Using Rider](installing-nightly-builds.md#option-3-using-rider) - -### Option 1: Using the command line - -To add the nightly feed using the command line: - -1. Open a command prompt of your choice. -2. Run the following command: - -``` -dotnet nuget add source "https://www.myget.org/F/umbraconightly/api/v3/index.json" -n "Umbraco Nightly" -``` - -Now the feed is added as a source named `Umbraco Nightly`. - -### Option 2: Using Visual Studio - -To add the nightly feed using Visual Studio: - -1. Open Visual Studio. -2. Go to **Tools** > **NuGet Package Manager** > **Package Manager Settings**. - -![Package Manager Settings](images/VS/open-nuget-setttings.jpg) - -3. The **Options** window open. -4. Select the **Package Sources** option in the **NuGet Package Manager** section. -5. Click the `+` icon. -6. A new Package source will be added automatically and highlighted. -7. Enter the desired name for the feed in the **Name** field. -8. Enter the link `https://www.myget.org/F/umbraconightly/api/v3/index.json` into the **Source** field. -9. Click **OK**. - -![Register the nightly feed](images/Nightly/Register_Nightly_Feed.jpg) - -Now the feed is added as a source named `Umbraco Nightly`. - -### Option 3: Using Rider - -To add the nightly feed using Rider: - -1. Open Rider. -2. Go to **View** > **Tool Windows** > **NuGet**. -3. Go to **Sources** tab. -4. Choose the `C:\Users\Úmbraco\AppData\Roaming\NuGet\NuGet.Config` to add the feed globally. -5. Click the green `+` button in the **New Feed** field. - -![Open the new feed menu](images/Nightly/NuGet_NewFeed.jpg) - -6. The New feed dialog opens. -7. Enter the desired name in the **Name** field. -8. Enter `https://www.myget.org/F/umbraconightly/api/v3/index.json` in the URL field. - -{% hint style="info" %} -Leave the **User, Password** fields empty, and the **Enabled** checkbox ticked. -{% endhint %} - -![Adding the feed](images/Nightly/NewFeed_Details.jpg) - -9. Click **OK**. - -Now the feed is added as a source named `Umbraco Nightly`. - -## Finding the latest nightly version - -In the previous steps, we've added the feed and are now ready to install the nightly build. - -However, which version should we install? This is, in particular, an issue if we want to create a new site using the dotnet template. The dotnet command does not allow us to use wildcard characters to install the newest version. - -Using IDE, we can see a list of available versions in both Visual Studio and Rider. We can then use that version to install the template. - -Here we're going to assume that you want to create a brand new site with the dotnet template. The approach is the same if you're updating an existing site. You'll click the **Update** button for the `Umbraco.Cms` package instead of installing the template through the terminal. - -Let's look at how we can find the latest version of the nightly build: - -* [Using Visual Studio](installing-nightly-builds.md#option-1-using-visual-studio) -* [Using Rider](installing-nightly-builds.md#option-2-using-rider) - -### Option 1: Using Visual Studio - -You can use the package manager in Visual Studio to browse the available template versions. - -1. Open Visual Studio. -2. Go to **Tools** > **NuGet Package Manager** > **Manage NuGet Packages For Solution...** - -![Opening the Nuget Package Manager](images/Nightly/Manage_NuGet_Pkgs.jpg) - -3. Select **Umbraco Nightly** from the **Package source** dropdown in the **NuGet - Solution** window. - -![Select the nightly NuGet feed](images/Nightly/Manage_Packages.jpg) - -4. Check the **Include prerelease** checkbox. -5. Search for **Umbraco.Templates** in the **Browse** field. -6. Choose that package. -7. Click on the **Version** dropdown and see the available nightly builds. -8. Choose the applicable version and note down the version number. - -![Find the version](images/Nightly/Latest_nightly_build_version.jpg) - -### Option 2: Using Rider - -You can use the NuGet window in Rider to browse the available template versions. - -1. Open Rider. -2. Go to the **Packages** tab in the **NuGet** window.. -3. Select **Umbraco Nightly** from the **All Feeds** dropdown. - -![Choose the feed](images/Nightly/Rider_Nightly_Feed.jpg) - -4. Check the **Prerelase** checkbox. -5. Search for **Umbraco.Templates** in the **Search** field. -6. Choose that package. -7. Click on the **Version** drop down and see the available nightly builds. -8. Choose the applicable version and note down the version number - -![Find the version](images/Nightly/Rider_Nightly_Feed_version.jpg) - -## Installing the latest nightly version template - -Now that our feed is added and we know the exact version we're ready to install our template. - -To install the latest nightly version template: - -1. Open your command prompt. -2. Run the following command using the latest version: - -``` -dotnet new install Umbraco.Templates -``` - -With that, we've successfully installed the latest nightly build of Umbraco. - -All we have to do now is to create a site using the `dotnet new umbraco -n MyAwesomeNightlySite` command. - -For more information about installing Umbraco, see the [Installation ](./)article. diff --git a/10/umbraco-cms/fundamentals/setup/install/running-umbraco-on-linux-macos.md b/10/umbraco-cms/fundamentals/setup/install/running-umbraco-on-linux-macos.md deleted file mode 100644 index 220d4f52161..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/running-umbraco-on-linux-macos.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -description: Since Umbraco 9 it has been possible to run Umbraco CMS natively on Linux/macOS. ---- - -# Running Umbraco On Linux/macOS - -With Umbraco CMS on .NET Core, Linux/macOS is natively supported with SQLite as the database. - -In the below section, we describe how to get started with running Umbraco CMS. - -## How to get started running Umbraco CMS on Linux/macOS - -To get started with Umbraco CMS first have a look at the [requirements for running Umbraco CMS with Linux/macOS](../requirements.md#local-development). - -Once you've made sure you meet the requirements it is time to install the Umbraco Templates on your system. - -To do this follow the [Install using .NET CLI](install-umbraco-with-templates.md#install-the-template) guide. - -With the templates installed on your system, it is now possible to create Umbraco projects. - -To create a project, there are two options: - -* Continue creating projects using the .NET CLI. -* Create new projects using Visual Studio. - -To create new projects using Visual Studio, you can use the [Install using Visual Studio](visual-studio.md) guide. - -Once you create a new project it will use SQLite by default. - -If you want to use an SQL server database, you will need to [set up Docker](https://skrift.io/issues/umbraco-and-docker-part-1-getting-familiar-with-containers/). diff --git a/10/umbraco-cms/fundamentals/setup/install/unattended-install.md b/10/umbraco-cms/fundamentals/setup/install/unattended-install.md deleted file mode 100644 index db425796b00..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/unattended-install.md +++ /dev/null @@ -1,144 +0,0 @@ -# Unattended Installs - -In some cases, you might need to install Umbraco instances automatically without having to run through the installation wizard to configure the instance. - -You can use the **Unattended installs** feature to allow for quick installation and set up of Umbraco instances on something like Azure Web Apps. - -This article will give you the details you need to install Umbraco unattended. - -## Get clean install of Umbraco - -In order to get a clean instance of Umbraco, follow our installation guide for how to [Install an Umbraco project template](install-umbraco-with-templates.md#install-umbraco-with-net-cli). - -## Configure your database - -As you will not be running through the installation wizard when using this feature, you need to manually tell Umbraco which database to use. - -* Set up and configure a new database - see [Requirements](../requirements.md#hosting) for details. -* Add the connection string using configuration. - -{% hint style="info" %} -Umbraco can create an SQL Server database for you during the unattended install process. The user specified by the credentials in your connection string needs to have the `CREATE DATABASE` permission granted and the global setting [InstallMissingDatabase](../../../reference/configuration/globalsettings.md#install-missing-database) is set to `true`. - -If your connection string is for SQLite or SQL Server Express LocalDB it is assumed that a database should be created when missing. This is regardless of the value of the `InstallMissingDatabase` setting. -{% endhint %} - -### SQL Server Example in appsettings.json - -```json -{ - "ConnectionStrings": { - "umbracoDbDSN": "server=localhost;database=UmbracoUnicore;user id=sa;password='P@ssw0rd'", - "umbracoDbDSN_ProviderName": "System.Data.SqlClient" - } -} -``` - -{% hint style="info" %} -The 'umbracoDbDSN_ProviderName' attribute sets the .NET Framework data provider name for the DataSource control's connection. For more information on the data providers included in the .Net Framework, see the [Microsoft Documentation](https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.sqldatasource.providername?#remarks). -{% endhint %} - -### SQLite Example in appsettings.json - -A value is configured for the key`umbracoDbDSN_ProviderName` to ensure usage of the `Microsoft.Data.SQLite` ADO.NET provider. - -It is recommended that you make use of the values shown below for the `Cache`, `Foreign Keys` and `Pooling` keywords on your connection string. - -```json -{ - "ConnectionStrings": { - "umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", - "umbracoDbDSN_ProviderName": "Microsoft.Data.SQLite" - } -} -``` - -## Enable the unattended installs feature - -The unattended installs feature is disabled by default. In order to enable it, you need to add the following JSON object to a JSON configuration source. - -```json -{ - "Umbraco": { - "CMS": { - "Unattended": { - "InstallUnattended": true, - "UnattendedUserName": "FRIENDLY_NAME", - "UnattendedUserEmail": "EMAIL", - "UnattendedUserPassword": "PASSWORD" - } - } - } -} -``` - -Remember to set the value of `InstallUnattended` to `true`. - -Alternatively you may set your configuration with Environment Variables or other means. Learn more about this in the [Microsoft .Net Core config documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0#environment-variables). - -The keys for this would then be as follows: - -``` -Umbraco__CMS__Unattended__InstallUnattended -Umbraco__CMS__Unattended__UnattendedUserName -Umbraco__CMS__Unattended__UnattendedUserEmail -Umbraco__CMS__Unattended__UnattendedUserPassword -``` - -## Initialize the unattended install - -After completing the steps above you can now initialize the installation by booting up the Umbraco instance. - -Once it has completed, you should see the following when visiting the frontend of the site. - -
- -## Configuration options - -Depending on your preferences, you can use any type of configuration to specify the connection string and login information, as well as enable unattended install. With the extending configuration functionality, it is possible to read from all kinds of sources. One example can be using a JSON file or environment variables. - -**Program.cs** has a condition, which if met, an _appsettings.Local.json_ file will be added and configured as a configuration source. - -``` -#if DEBUG - .ConfigureAppConfiguration(config - => config.AddJsonFile( - "appsettings.Local.json", - optional: true, - reloadOnChange: true)) -#endif -``` - -Having intellisense will help you to add your connection string and information needed for the unattended install. - -```json -{ - "ConnectionStrings": { - "umbracoDbDSN": "server=localhost;database=UmbracoUnicore;user id=sa;password='P@ssw0rd'" - }, - "Umbraco": { - "CMS": { - "Unattended": { - "InstallUnattended": true, - "UnattendedUserName": "FRIENDLY_NAME", - "UnattendedUserEmail": "EMAIL", - "UnattendedUserPassword": "PASSWORD" - } - } - } -} -``` - -## More support - -We have added support for unattended installs with Name, Email and Password, and Connection String as CLI params, which are also available in Visual Studio. There you can fill in your information as follows: - -### CLI - -```powershell -dotnet new umbraco -n MyNewProject --friendly-name "Friendly User" --email user@email.com --password password1234 --connection-string "Server=(localdb)\Umbraco;Database=MyDatabase;Integrated Security=true" --version 10.0.0 -``` - -### Visual Studio - -
diff --git a/10/umbraco-cms/fundamentals/setup/install/visual-studio.md b/10/umbraco-cms/fundamentals/setup/install/visual-studio.md deleted file mode 100644 index 13a7bc33458..00000000000 --- a/10/umbraco-cms/fundamentals/setup/install/visual-studio.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -description: A guide to install Umbraco CMS using Visual Studio. ---- - -# Install using Visual Studio - -## Prerequisites - -* Install the newest [Umbraco dotnet templates](install-umbraco-with-templates.md). - * In Visual Studio 2022, the .NET CLI templates are enabled to appear, by default. For information on how to enable .NET CLI templates in Visual Studio 2019, see the [.NET CLI Templates in Visual Studio](https://devblogs.microsoft.com/dotnet/net-cli-templates-in-visual-studio/) article. -* Check the [Requirements](../requirements.md) to ensure you have everything you need to start your Umbraco project. - -## Quick start - -This is an abbreviated version of the installation steps. Jump to the [Create a new project](visual-studio.md#new-project) section for a more thorough guide. - -* Open Visual Studio. -* Go to `File` > `New` > `Project`, search for **Umbraco**. -* Choose **Umbraco Project (Umbraco HQ)** then click **Next**. -* Choose or specify the parameters, leave the default or leave them all empty. -* Click **Create**. -* Use **CTRL+F5** to run the project and start the Umbraco installer. - -## Video Tutorial - -{% embed url="https://www.youtube.com/watch?ab_channel=UmbracoLearningBase&v=CDeAYGu_-cI" %} -How to install Umbraco using NuGet and Visual Studio -{% endembed %} - -## Create a new Umbraco project - -To install Umbraco we first need to install Umbraco's dotnet new templates. - -For more information check the first 2 steps of the [Install Umbraco with .NET CLI article](install-umbraco-with-templates.md#install-the-template). - -### Create the Visual Studio project - -Go to **File > New > Project** and search for `Umbraco` in the _Search for templates_ field. - -![The Create a new project dialog in Visual Studio.](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VS/create-project.png) - -Once you select **Umbraco Project (Umbraco HQ)** navigate to the next step by selecting _Next_. - -### Configure the project - -In this step, you will be able to give your project a name specific to the project you are creating. - -![The Configure your new project dialog in Visual Studio.](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VS/configure-project.png) - -{% hint style="info" %} -Refrain from changing the Solution name, as this will cause a namespace conflict with the CMS itself. -{% endhint %} - -### Adding additional information - -In the next step, you are able to specify some additional parameters like the _Target framework_. The rest are optional. - -![The Additional information dialog in Visual Studio.](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VS/Umbraco10\_install.png) - -You can then click the _Create_ button and your Umbraco Project will be ready for you. - -![Overview of files in the project solution](../../../../../13/umbraco-cms/fundamentals/setup/install/images/VS/ready-solution.png) - -### Running the site - -You can now run the site through Visual Studio using **F5** or the **Debug** button. - -Follow the installation wizard and after a few steps, you will get a message saying the installation was a success. - -## Next steps - -You are now ready to start building your Umbraco project. Have a look below for different resources on the next steps. - -* [Getting Started with Umbraco](../../../../getting-started/) -* [Tutorial: Create a website from scratch](../../../tutorials/creating-a-basic-website/) -* [Find different options for hosting your Umbraco website](../server-setup/) -* [Learn about configuration in Umbraco CMS](../../../reference/configuration/) diff --git a/10/umbraco-cms/fundamentals/setup/requirements.md b/10/umbraco-cms/fundamentals/setup/requirements.md deleted file mode 100644 index a13d31120bf..00000000000 --- a/10/umbraco-cms/fundamentals/setup/requirements.md +++ /dev/null @@ -1,71 +0,0 @@ -# Requirements - -## Browsers - -The Umbraco UI should work in all modern browsers: - -* Chrome (Latest) -* Edge (Chromium) -* Firefox (Latest) -* Safari (Latest) - -## Local Development - -Below you can find the minimum requirements to run Umbraco 10 on your machine: - -* [.NET 6.0.5 and higher](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) -* One of the [.NET 6 - Supported OS versions](https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md) -* One of the following .NET Tools or Editors: - * [Visual Studio Code](https://code.visualstudio.com/) with the [IISExpress extension](https://marketplace.visualstudio.com/items?itemName=warren-buckley.iis-express) - * [Microsoft Visual Studio](https://www.visualstudio.com/) 2022 version 17.0 or higher. - * Optional: [JetBrains Rider](https://www.jetbrains.com/rider) version 2022.3 and higher - * [.NET Core CLI](install/install-umbraco-with-templates.md) -* [SQL connection string (SQL Server)](../../reference/configuration/connectionstringssettings.md) - -{% hint style="info" %} -When using Visual Studio as your primary Integrated Development Environment (IDE) we recommend [finding and downloading the Software Development Kits (SDKs) for Visual Studio](https://dotnet.microsoft.com/en-us/download/visual-studio-sdks). -{% endhint %} - -## Hosting - -### Recommendation requirements to run Umbraco - -As Umbraco releases are aligned to the .NET release cadence, it's also aligned with Microsoft's Long-term support policy for the underlying framework. For the best experience, we would recommend that you ensure to be on latest and supported Microsoft versions to run and host Umbraco CMS: - -* [Windows Supported releases](https://learn.microsoft.com/en-us/dotnet/core/install/windows?tabs=net70#supported-releases) -* [MacOs Supported releases](https://learn.microsoft.com/en-us/dotnet/core/install/macos#supported-releases) -* [Ubuntu Supported distributions](https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#supported-distributions) and other [Linux Packages](https://learn.microsoft.com/en-us/dotnet/core/install/linux#packages) -* [.NET Supported releases](https://dotnet.microsoft.com/en-us/platform/support/policy) - -{% hint style="info" %} -For the above, as Umbraco version 10 is based on .NET 6 you will need to follow the .NET 6 supported versions. -{% endhint %} - -* [IIS Supported releases](https://learn.microsoft.com/en-us/lifecycle/products/internet-information-services-iis) -* [SQL Server Supported releases](https://learn.microsoft.com/en-us/sql/sql-server/end-of-support/sql-server-end-of-support-overview?view=sql-server-ver16#lifecycle-dates) -* [SQLite](https://www.sqlite.org/index.html) - -As Umbraco version 10 is based on .NET 6 follow the requirements for .NET 6. - -_For more information, see the_ [_Host and deploy ASP.NET Core applications_](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/?view=aspnetcore-6.0) _article in the Microsoft documentation._ - -{% hint style="success" %} -You can use [Umbraco Cloud](https://umbraco.com/products/umbraco-cloud/) to manage the hosting infrastructure. All Umbraco Cloud plans are hosted on Microsoft Azure, which gives your site a proven and solid foundation. -{% endhint %} - -### Other recommendation - -* Ability to set file permissions to include create/read/write (or better) for the user that "owns" the Application Pool for your site. This would typically be **NETWORK SERVICE**. - -## Database Account Roles - -The database account used in the connection string will need permissions to read and write from tables. It will also require permission to create schema during installs and upgrades: - -* The `db_owner` role has full permissions on the database. -* To use an account with more restricted permissions, the `db_datareader` and `db_datawriter` roles will be needed for normal use to read from and write to the database. The `db_ddladmin` role, which can modify the database schema, is required for installs and upgrades of the CMS and/or any packages that create database tables. - -For more information on the Database-level roles, see the [Microsoft documentation](https://docs.microsoft.com/en-us/sql/relational-databases/security/authentication-access/database-level-roles?view=sql-server-ver16#fixed-database-roles). - -{% hint style="info" %} -For more information on how to create a database user via SQL, you can check the [Microsoft documentation](https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/database-level-roles?view=sql-server-ver16#a--adding-a-user-to-a-database-level-role). -{% endhint %} diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/README.md b/10/umbraco-cms/fundamentals/setup/server-setup/README.md deleted file mode 100644 index 0a057a0da5a..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/README.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -meta.Title: "Information on server setup for Umbraco hosting" -description: "This section describes different ways of setting up servers for use with Umbraco" ---- - -# Server setup - -*This section describes different ways of setting up servers for use with Umbraco* - -## Secure Sockets Layer (SSL) and HTTPS - -We strongly encourage the use of HTTPS with Umbraco installations especially in production environments. Using HTTPS will greatly enhance the security of your website, see the [Security reference](../../../reference/security/README.md) for more information. - -## [File & folder permissions](permissions.md) - -To ensure a stable and smoothly running Umbraco installation, these permissions need to be set correctly. - -## [Hosting v9+ in IIS](iis.md) - -Information about hosting a v9 application using IIS. - -## [Load Balanced setup](load-balancing/README.md) - -Information on how to deploy Umbraco in a Load Balanced scenario and other details to consider when setting up Umbraco for load balancing. - -## [Running Umbraco on Azure Web Apps](azure-web-apps.md) - -Best practices for running Umbraco on Azure Web Apps. - -## [Runtime modes](runtime-modes.md) - -The runtime mode setting optimizes Umbraco for the best development experience or optimal production environment. - -## [Running Umbraco in Docker](running-umbraco-in-docker.md) - -Overview of topics to consider when running Umbraco in Docker. diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/azure-web-apps.md b/10/umbraco-cms/fundamentals/setup/server-setup/azure-web-apps.md deleted file mode 100644 index 415463f1de4..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/azure-web-apps.md +++ /dev/null @@ -1,95 +0,0 @@ -# Running Umbraco On Azure Web Apps - -This section describes best practices with running Umbraco on Azure Web Apps - -## What are Azure Web Apps - -They have been called a few names in the past, many people still know Azure Web Apps as Azure Web Sites. - -> App Service is a fully Managed Platform for professional developers that brings a rich set of capabilities to web, mobile and integration scenarios. Quickly create and deploy mission critical web Apps that scale with your business by using Azure App Service. - -[You can read more about them here](https://azure.microsoft.com/en-us/documentation/articles/app-service-web-overview/) - -Umbraco will run on Azure Web Apps but there are some configuration options and specific Azure Web Apps environment limitations to be aware of. - -## Recommended configuration - -You need to add these configuration values. E.g in a json configuration source like `appSettings.json`: - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "MainDomLock" : "FileSystemMainDomLock" - }, - "Hosting": { - "LocalTempStorageLocation": "EnvironmentTemp" - }, - "Examine": { - "LuceneDirectoryFactory": "SyncedTempFileSystemDirectoryFactory" - } - } - } -} -``` - -You can also copy the following JSON directly into your Azure Web App configuration via the Advanced Edit feature. - -

Advanced edit

- -```json -{ - "name": "UMBRACO__CMS__Global__MainDomLock", - "value": "FileSystemMainDomLock", - "slotSetting": false -}, -{ - "name": "UMBRACO__CMS__Hosting__LocalTempStorageLocation", - "value": "EnvironmentTemp", - "slotSetting": false -}, -{ - "name": "UMBRACO__CMS__Examine__LuceneDirectoryFactory", - "value": "SyncedTempFileSystemDirectoryFactory", - "slotSetting": false -} -``` - -The minimum recommended Azure SQL Tier is "S2", however noticeable performance improvements are seen in higher Tiers - -If you are load balancing or require the scaling ("scale out") ability of Azure Web Apps then you need to consult the [Load Balancing documentation](load-balancing/). This is due to the fact that a lot more needs to be configured to support scaling/auto-scaling. - -## Storage - -It is important to know that Azure Web Apps uses a remote file share to host the files to run your website. This is due to the files running your website do not exist on the machine running your website. In many cases this isn't an issue. It can become one if you have a large amount of IO operations running over remote file-share. - -## Issues with read-only filesystems - -Although Umbraco can be configured to use environmental storage it still requires its working-directory to be writable. If Umbraco is deployed to a read-only file system it will [fail to boot](https://github.com/umbraco/Umbraco-CMS/issues/12043). - -For example, Azure's [Run from Package feature](https://docs.microsoft.com/en-us/azure/app-service/deploy-run-package) is not supported by Umbraco. To check if your web app is using this feature you can check the `WEBSITE_RUN_FROM_PACKAGE` environment variable. - -## Scaling - -If you require the scaling ("scale out") ability of Azure Web Apps you need to consult the [Load Balancing documentation](load-balancing/). This is due to the fact that a lot more needs to be configured to support scaling/auto-scaling. - -## Web worker migrations - -It's important to know that Azure Web Apps may move your website between their 'workers' at any given time. This is normally a transparent operation. In some cases you may be affected by it if any of your code or libraries use the following variables: - -* `Environment.MachineName` (or equivalent) - -When your site is migrated to another worker, these variables will change. You cannot rely on these variables remaining static for the lifetime of your website. - -### How to find the Linux App Service Logs - -The quickest way to get to your logs is using the following URL template and replacing `{app}` with your Web App name: - -`https://{app}.scm.azurewebsites.net/api/logstream` - -You can also find this in the KUDU console by clicking **Advanced Tools** > **Log Stream** on the Web App in the Azure Portal. - -## Web App secret management - -Consult the [Azure Key Vault documentation](../../../extending/key-vault.md#use-key-vault-references-for-azure-app-service) if you would like to directly reference Azure Key Vault Secrets to your Azure Web App. diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/iis.md b/10/umbraco-cms/fundamentals/setup/server-setup/iis.md deleted file mode 100644 index c66d7d9ea87..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/iis.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -meta.Title: Hosting v9+ in IIS -description: Information on hosting Umbraco v9+ on IIS ---- - -# Hosting Umbraco in IIS - -## Configuring IIS for .NET 5 - -* Install the [".NET Core Runtime"](https://dotnet.microsoft.com/en-us/download/dotnet/) and download the **Hosting Bundle**. Ensure you download the correct .NET version as per the [requirements](../requirements.md). -* Once you have the hosting bundle installed and have restarted IIS (`net stop was /y` followed by `net start w3svc`), create a site in IIS as you would for a v8 site, however you need to ensure that ".NET CLR version" is set to "No Managed Code" for the Application Pool. - -![IIS Application Pool](images/iis-app-pool-core.png) - -### Publish website for manual deployment to IIS - -You can use the dotnet CLI to compile and collate all files required for hosting - -```none -dotnet publish -o ../deployment-artefacts -f net5.0 -``` - -Alternatively you can use folder or ftp publishing in Visual Studio to compile and collate all required files to for the application to run. - -In Visual Studio right click on Umbraco web project in the _Solution Explorer_ and choose _Publish..._ command. - -![Publish...](images/contextmenu-publish-command.jpg) - -{% hint style="info" %} -**Deploy a website for automated deployment with Azure DevOps to IIS** - -You can use the [IIS Release task in Azure DevOps](https://learn.microsoft.com/en-us/azure/devops/pipelines/release/deploy-webdeploy-iis-deploygroups) to deploy your website to your Web Server. This task is a wrapper for `MSDeploy.exe` and can be configured as preferred. -{% endhint %} - -### Environment Variables in ApplicationHost.config - -In the _Management_ section you find the _Configuration Editor_: - -![IIS Website Configuration](images/iis-core-website-config.png) - -One section is of particular interest: - -* In the first, left hand dropdown list (_Section:_) choose: `system.webServer/aspNetCore` section. -* In the second, right hand dropdown list (_From:_) choose: `ApplicationHost.config `. This ensures your settings will be stored in a machine specific file and not the website's web.config. The web.config might end in a public repository and should not contain sensitive data like Connection Strings or SMTP configuration with username and password. Additionally by default the web.config will be overwritten during each publish processes. - -![IIS Configuration Editor](images/iis-environment-variables.png) - -Find the line named _environmentVariables_ and open the dialog to add environment variables. These work similar to the _launchSettings_. E.g. you can define `ASPNETCORE_ENVIRONMENT` and create an `appSettings.[ASPNETCORE_ENVIRONMENT].json` file. Or even better create environment variables for sensitive settings like passwords. There are some differences to `launchSettings.json` configuration: - -* Variable names need to change the object structure form JSON by combining the segments with double underscore `__` e.g. `ConnectionStrings__umbracoDbDSN` -* escaped backslashes `\\` e.g. `serverName\\databaseInstanceName` are replaced by single backslash `\` e.g. `DATABASESERVER123\SQL2017` - -### IIS Hosting models - -IIS can host .NET 5 applications using 2 different hosting models - -* [In-process (default)](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/in-process-hosting?view=aspnetcore-5.0) -* In-process hosting runs an .NET 5 app in the same process as its IIS worker process -* [Out-of-process](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/out-of-process-hosting?view=aspnetcore-5.0) - to enable this model you need to edit your .csproj file and add: - -```js - - OutOfProcess - -``` - -Out-of-process .NET 5 apps run in a separate from the IIS worker process. The module controls the management of the Kestrel server and requests are proxied between them. diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/images/contextmenu-publish-command.jpg b/10/umbraco-cms/fundamentals/setup/server-setup/images/contextmenu-publish-command.jpg deleted file mode 100644 index 5e4c10665cf..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/images/contextmenu-publish-command.jpg and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-app-pool-core.png b/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-app-pool-core.png deleted file mode 100644 index 09e0a3b14c7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-app-pool-core.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-core-website-config.png b/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-core-website-config.png deleted file mode 100644 index 906af9f7875..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-core-website-config.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-environment-variables.png b/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-environment-variables.png deleted file mode 100644 index eca4129d499..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/images/iis-environment-variables.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/README.md b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/README.md deleted file mode 100644 index 4bec62a5f97..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/README.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -meta.Title: Umbraco in Load Balanced Environments -description: >- - Information on how to deploy Umbraco in a Load Balanced scenario and other - details to consider when setting up Umbraco for load balancing ---- - -# Umbraco in Load Balanced Environments - -_Information on how to deploy Umbraco in a Load Balanced scenario and other details to consider when setting up Umbraco for load balancing._ - -## Overview - -Configuring and setting up a load balanced server environment requires planning, design and testing. This document should assist you in setting up your servers, load balanced environment and Umbraco configuration. - -This document assumes that you have a fair amount of knowledge about: - -* Umbraco -* IIS 10+ -* Networking & DNS -* Windows Server -* .NET5+ - -{% hint style="info" %} -It is highly recommended that you setup your staging environment to also be load balanced so that you can run all of your testing on a similar environment to your live environment. -{% endhint %} - -## Design - -These instructions make the following assumptions: - -* All web servers can communicate with the database where Umbraco data is stored -* You are running Umbraco 9.0.0 or above -* _**You will designate a single server to be the backoffice server for which your editors will log into for editing content.**_ Umbraco will not work correctly if the backoffice is behind the load balancer. - -There are three design alternatives you can use to effectively load balance servers: - -1. You use cloud based auto-scaling appliances like [Microsoft's Azure Web Apps](https://azure.microsoft.com/en-us/services/app-service/web/) -2. Each server hosts copies of the load balanced website files and a file replication service is running to ensure that all files on all servers are up to date -3. The load balanced website files are located on a centralized file share (SAN/NAS/Clustered File Server/Network Share) - -You will need a load balancer to do your load balancing. - -## How Umbraco load balancing works - -In order to understand how to host your site it is best to understand how Umbraco's flexible load balancing works. - -The following diagram shows the data flow/communication between each item in the environment: - -![Umbraco flexible load balancing diagram](images/flexible-load-balancing-v9.png) - -The process is as follows: - -* Administrators and editors create, update, delete data/content on the backoffice server -* These events are converted into data structures called "instructions" and are stored in the database in a queue -* Each front-end server checks to see if there are any outstanding instructions it hasn't processed yet -* When a front-end server detects that there are pending instructions, it downloads them and processes them and in turn updates it's cache, cache files and indexes on its own file system -* There can be a delay between content updates and a front-end server's refreshing, this is expected and normal behaviour. - -## Scheduling and server role election - -Although there is a backoffice server designated for administration, by default this is not explicitly set as the "Scheduling server". In Umbraco there can only be a single scheduling server which performs the following 3 things: - -* Keep alive service - to ensure scheduled publishing occurs -* Scheduled tasks - to initiate any configured scheduled tasks -* Scheduled publishing - to initiate any scheduled publishing for documents - -### Automatic Server Role Election - -Umbraco will automatically elect a "Scheduling server" to perform the above services. This means that all of the servers will need to be able to resolve the URL of either: itself, the Backoffice server, the internal load balancer, or the public address. - -There are two server roles: - -* `SchedulingPublisher` - Usually this is the backoffice instance. -* `Subscriber` - These are the scalable front-end instances - not recommended to be used for backoffice access. - -{% hint style="info" %} -These new terms replace 'Master and Replica', in Umbraco versions 7 and 8. -{% endhint %} - -Each instance will be allocated a role by the automatic server role election process, but they can also be set explicitly (recommended) - -For example, In the following diagram the node **f02.mysite.local** is the elected "Scheduling server". In order for scheduling to work it needs to be able to send requests to itself, the Backoffice server, the internal load balancer or the public address. The address used by the "Scheduling server" is called the "umbracoApplicationUrl". - -![Umbraco flexible load balancing diagram](images/flexible-load-balancing-scheduler-v9.png) - -By default, Umbraco will set the "umbracoApplicationUrl" to the address made by the first accepted request when the AppDomain starts. It is assumed that this address will be a DNS address that the server can resolve. - -For example, if a public request reached the load balancer on `www.mysite.com`, the load balancer may send the request on to the servers with the original address: `www.mysite.com`. By default the "umbracoApplicationUrl" will be `www.mysite.com`. However, load balancers may route the request internally under a different DNS name such as "f02.mysite.local" which by default would mean the "umbracoApplicationUrl" is "f02.mysite.local". In any case the elected "Scheduling server" must be able to resolve this address. - -In many scenarios this is fine, but in case this is not adequate there's a few of options you can use: - -* **Recommended**: [set your front-end(s) (non-admin server) to be explicit subscriber servers](flexible-advanced.md#explicit-schedulingpublisher-server) by creating a custom `IServerRegistrar`, this means the front-end servers will never be used as the SchedulingPublisher server role. -* Set the `UmbracoApplicationUrl` property in the [WebRouting section of the CMS config](../../../../reference/configuration/webroutingsettings.md) - -## Common load balancing setup information - -_The below section applies to all ASP.NET load balancing configurations._ - -## Server Configuration - -This section describes the configuration options depending on your hosting setup: - -1. [Azure Web Apps](file-system-replication.md#mixture-of-standalone--synchronised) - _You use cloud based auto-scaling appliances like_ [_Microsoft's Azure Web Apps_](https://azure.microsoft.com/en-us/services/app-service/web/) -2. [File Replication](file-system-replication.md#synchronised-file-system) - _Each server hosts copies of the load balanced website files and a file replication service is running to ensure that all files on all servers are up to date_ -3. [Centralized file share](file-system-replication.md#synchronised-file-system) - _The load balanced website files are located on a centralized file share (SAN/NAS/Clustered File Server/Network Share)_ - -[Full documentation is available here](file-system-replication.md) - -### Data Protection - -The replacement for Machine Keys in ASP.NET Core are called Data Protection. You will need to setup data protection to the same keys on all servers, without this you will end up with view state errors, validation errors and encryption/decryption errors since each server will have its own generated key. - -ASP.NET Core supports multiple ways to share keys. Use the [official docs](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) to find a description that fits your setup the best. - -### Session State and Distributed Cache - -It is required to setup a distributed cache, like `DistributedSqlServerCache` or an alternative provider (see [https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) for more details). The distributed cache is used by the session in your application, which is used by the default TempDataProvider in MVC. - -Because Umbraco in some cases uses TempData, your setup needs to be configured with a distributed cache. - -### Logging - -There are some logging configurations to take into account no matter what type of load balancing environment you are using. - -[Full documentation is available here](logging.md) - -### Testing - -Your staging environment should also be load balanced so that you can see any issues relating to load balancing in that environment before going to production. - -You'll need to test this solution **a lot** before going to production. You need to ensure there are no windows security issues, etc... The best way to determine issues is have a lot of people testing this setup and ensuring all errors and warnings in your application/system logs in Windows are fixed. - -Ensure to analyze logs from all servers and check for any warnings and errors. - -## Unattended upgrades - -When upgrading it is possible to run the upgrades unattended. - -Find steps on how to enable the feature for a load balanced setup in the [General Upgrades](../../upgrading/#unattended-upgrades-in-a-load-balanced-setup) article. - -## FAQs - -_Here's some common questions that are asked regarding Load Balancing with Umbraco:_ - -**Question>** _Why do I need to have a single web instance for Umbraco admin?_ - -_TL:DR_ You must not load balance the Umbraco backoffice, you will end up with data integrity or corruption issues. - -The reason you need a single server is because there is no way to guarantee transactional safety between servers. This is because we don't currently use database level locking, we only use application (c#) level locks to guarantee transactional data integrity which is only possible to work on one server. If you have multiple admins saving and publishing at once between servers then the order in which this data is read and written to the database absolutely must be consistent otherwise you will end up with data corruption. - -Additionally, the order in which cache instructions are written to the cache instructions table is important for LB, this order is guaranteed by having a single admin server. - -**Question>** _Can my SchedulingPublisher backoffice admin server also serve front-end requests?_ - -Yes. There are no problems with having your SchedulingPublisher backoffice admin server also serve front-end request. - -However, if you wish to have different security policies for your front-end servers and your back office servers, you may choose to not do this. diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/azure-web-apps.md b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/azure-web-apps.md deleted file mode 100644 index 41d5081e258..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/azure-web-apps.md +++ /dev/null @@ -1,114 +0,0 @@ -# Load Balancing Azure Web Apps - -Ensure you read the [Load Balancing overview](./) and general [Azure Web Apps](../azure-web-apps.md) documentation before you begin - you will need to ensure that your ASP.NET Core & logging configurations are correct. - -## Azure Requirements - -* 2 x App service plans with 1 x web app in each: - * One for the backoffice (Administrative) environment - * One for your scalable public-facing environment (Public) -* 1 x SQL server that is shared with these 2 web apps - -The setup above will allow for the proper scaling of the Administrative and Public web apps. - -The App Service plan with the Administrative web app should only be scaled up. The reason for this is that the web app needs to stay as a single instance. - -The App Service plan with the Public web app can be scaled both out and up. - -## Lucene/Examine configuration - -The single instance Backoffice Administrative Web App should be set to use [SyncedTempFileSystemDirectoryFactory](file-system-replication.md#examine-directory-factory-options). - -The multi-instance Scalable Public Web App should be set to use [TempFileSystemDirectoryFactory](file-system-replication.md#examine-directory-factory-options). - -## Umbraco TEMP files - -When an instance of Umbraco starts up it generates some 'temporary' files on disk. In a normal IIS environment, these would be created within the folders of the Web Application. In an Azure Web App, we want these to be created in the local storage of the actual server that Azure happens to be used for the Web App. So we set this configuration setting to 'true' and the temporary files will be located in the environment temporary folder. This is required for both the performance of the website as well as to prevent file locks from occurring due to the nature of Azure Web Apps shared files system. - -```json -{ - "Umbraco": { - "CMS": { - "Hosting": { - "LocalTempStorageLocation" : "EnvironmentTemp" - } - } - } -} -``` - -{% tabs %} -{% tab title="Latest version" %} -#### Host synchronization - -Umbraco runs within a [.NET Host](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-6.0). - -When a host restarts, the current host 'winds down' while another host is started. This means there can be more than one live host during a restart. Restarts can occur in many scenarios including when an Azure Web App auto-transitions between hosts, you scale the instances or you utilize slot swapping. - -Some file system based services in Umbraco such as the Published Cache and Lucene files can only be accessed by a single host at once. Umbraco manages this synchronization by an object called `IMainDom`. - -By default **Umbraco v9.4 & 9.5** uses a system-wide semaphore locking mechanism. This mechanism only works on Windows systems and doesn't work with multi-instance Azure Web Apps. We need to swap it out for an alternative file system based locking mechanism by using the following appSetting. With **Umbraco v10+** `FileSystemMainDomLock` is the default setting. - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "MainDomLock" : "FileSystemMainDomLock" - } - } - } -} -``` - -Apply this setting to both the **SCHEDULINGPUBLISHER** Administrative server and the **SUBSCRIBER** scalable public-facing servers. -{% endtab %} - -{% tab title="9.0.0 - 9.4.0" %} -#### AppDomain synchronization - -Each application runs inside an [AppDomain](https://docs.microsoft.com/en-us/dotnet/framework/app-domains/application-domains) which is like a subprocess within the web app process. When an ASP.Net application restarts, the current AppDomain 'winds down' while another AppDomain is started; meaning there can be more than 1 live AppDomain during a restart. Restarts can occur in many scenarios including when an Azure Web App auto transitions between hosts, you scale the instances or you utilize slot swapping. - -Some file system based services in Umbraco such as the Published Cache and Lucene files can only be accessed by a single AppDomain at once. Umbraco manages this synchronization by an object called `IMainDom`. By default, this uses a system-wide locking mechanism but this default mechanism doesn't work in Azure Web Apps so we need to swap it out for an alternative database locking mechanism by using the following appSetting: - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "MainDomLock" : "SqlMainDomLock" - } - } - } -} -``` - -Apply this setting to both the **SCHEDULINGPUBLISHER** Administrative server and the **SUBSCRIBER** scalable public-facing servers. -{% endtab %} -{% endtabs %} - -## Steps to set-up an environment - -1. Create an Azure SQL database -2. Install Umbraco on your backoffice administrative environment and ensure to use your Azure SQL Database -3. Install Umbraco on your scalable public-facing environment and ensure to use your Azure SQL Database -4. Test: Perform some content updates on the administrative environment, ensure they work successfully in that environment, then verify that those changes appear on the scalable public-facing environment -5. Fix the backoffice environment to be the SCHEDULINGPUBLISHER scheduling server and the scalable public-facing environment to be SUBSCRIBERs - see [Setting Explicit Server Roles](flexible-advanced.md#explicit-schedulingpublisher-server) - -{% hint style="info" %} -Ensure all Azure resources are in the same region to avoid connection lag. -{% endhint %} - -## Scaling - -**Do not scale your backoffice administrative environment** this is not supported and can cause issues. - -The public-facing subscriber Azure Web Apps can be manually or automatically scaled up or down and is supported by Umbraco's load balancing. - -## Deployment considerations - -Since you have 2 x web apps, when you deploy you will need to deploy to both places - There are various automation techniques you can use to simplify the process. That is outside the scope of this article. - -{% hint style="info" %} -This also means that you should not be editing templates or views on a live server as SchedulingPublisher and Subscriber environments do not share the same file system. Changes should be made in a development environment and then pushed to each live environment. -{% endhint %} diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/file-system-replication.md b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/file-system-replication.md deleted file mode 100644 index aaa82324f4e..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/file-system-replication.md +++ /dev/null @@ -1,115 +0,0 @@ -# Standalone File System - -{% hint style="info" %} -No file replication is configured, deployment handles updating files on the different servers. -{% endhint %} - -If the file system on your servers isn't performing any file replication then no _Umbraco_ configuration file changes are necessary. However Media will need to be configured to use a shared location such as Blob storage or S3. - -Depending on the configuration and performance of the environment's local storage you might need to consider [Examine Directory Factory Options](file-system-replication.md#examine-directory-factory-options) and the [Umbraco temporary storage location](https://our.umbraco.com/documentation/Reference/Configuration-for-Umbraco-7-and-8/webconfig/#umbracocorelocaltempstorage). - -## Synchronised File System - -{% hint style="info" %} -The servers are performing file replication, updates to a file on one server, updates the corresponding file on any other servers. -{% endhint %} - -If the file system on your servers is performing file replication then the Umbraco temporary folder (`~/umbraco/Data/TEMP`) must be excluded from replication. - -If the file system on your servers is located on shared storage you will need to configure Umbraco to locate the Umbraco temporary folder outside of the shared storage. - -### Replication techniques - -A common way to replicate files on Windows Server is to use \[DFS]\(https://msdn.microsoft.com/en-us/library/windows/desktop/bb540031(v=vs.85), which is included with Windows Server. - -Additional DFS resources: - -* [Overview of DFS Replication in Windows Server 2008 R2](https://technet.microsoft.com/en-us/library/cc771058.aspx) -* [Watch an intro to installing and working with DFS](https://www.youtube.com/watch?v=DYfBoUt2RVE) - -There are other alternatives for file replication out there, some free and some licensed. You'll need to decide which solution is best for your environment. - -### Non-replicated files - -When deploying Umbraco in a load balanced scenario using file replication, it is important to ensure that not all files are replicated - otherwise you will experience file locking issues. Here are the folders and files that should not be replicated: - -* `~/umbraco/Data/TEMP/*` - -{% hint style="info" %} -Alternatively store the Umbraco temporary files in the local server's 'temp' folder and set Examine to use a [Directory Factory](file-system-replication.md#examine-directory-factory-options). - -Achieve this by changing the value of the `LuceneDirectoryFactory` setting to 'TempFileSystemDirectoryFactory' in the `appsettings.json`. The downside is that if you need to view temporary files you'll have to find it in the temp files. Locating the file this way isn't always clear. - -Below is shown how to do this in a Json configuration source. - -```json -{ - "Umbraco": { - "CMS": { - "Examine": { - "LuceneDirectoryFactory" : "TempFileSystemDirectoryFactory" - } - } - } -} -``` -{% endhint %} - -* `~/umbraco/Logs/*` - * This is **optional** and depends on how you want your logs configured (see below) - -If for some reason your file replication solution doesn't allow you to not replicate specific files folders (which it should!!) then you can use an alternative approach by using virtual directories. - -The following is not the recommended setup but it is a viable alternative: - -* Copy the `~/umbraco/Data/TEMP` directory to each server, outside of any replication areas or to a unique folder for each server. -* Create a virtual directory (not a virtual application) in the `~/umbraco/Data/` folder, and name it `TEMP`. Point the virtual directory to the folder you created in step 2. -* You may delete the `~/umbraco/Data/TEMP` folder from the file system - not IIS as this may delete the virtual directory - if you wish. - -### IIS Setup - -IIS configuration is pretty straightforward with file replication. IIS is only reading files from its own file system like a normal IIS website. - -## Mixture of standalone & synchronised - -In some scenarios you have a mixture of standalone and synchronised file systems. An example of this is Azure Web Apps where the file system isn't replicated between backoffice and front end servers but is replicated between all front end servers, in this configuration you should follow the steps for synchronised file systems. - -There is a specific documentation for load balancing with [Azure Web Apps](azure-web-apps.md) - -## Examine Directory Factory Options - -* The `TempFileSystemDirectoryFactory` allows Examine to store indexes directly in the environment temporary storage directory, and should be used instead of `SyncTempEnvDirectoryFactory` mentioned above. - -```json -{ - "Umbraco": { - "CMS": { - "Examine": { - "LuceneDirectoryFactory" : "TempFileSystemDirectoryFactory" - } - } - } -} -``` - -* The `SyncedTempFileSystemDirectoryFactory` enables Examine to sync indexes between the remote file system and the local environment temporary storage directory, the indexes will be accessed from the temporary storage directory. This setting is needed because Lucene has issues when working from a remote file share so the files need to be read/accessed locally. Any time the index is updated, this setting will ensure that both the locally created indexes and the normal indexes are written to. This will ensure that when the app is restarted or the local environment temp files are cleared out that the index files can be restored from the centrally stored index files. - -```json -{ - "Umbraco": { - "CMS": { - "Examine": { - "LuceneDirectoryFactory" : "SyncedTempFileSystemDirectoryFactory" - } - } - } -} -``` - -{% hint style="info" %} -If you are load balancing with [Azure Web Apps](azure-web-apps.md) make sure to check out the article we have for that specific set-up. -{% endhint %} - -## Advanced techniques - -Once you are familiar with how flexible load balancing works, you might be interested in some [advanced techniques](flexible-advanced.md). diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/flexible-advanced.md b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/flexible-advanced.md deleted file mode 100644 index afa92f78c19..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/flexible-advanced.md +++ /dev/null @@ -1,104 +0,0 @@ -# Advanced Techniques With Flexible Load Balancing - -_This describes some more advanced techniques that you could achieve with flexible load balancing_ - -The election process that runs during the startup of an Umbraco instance determines the server role that instance will undertake. - -There are two server roles to be aware of for flexible load balancing: - -* `SchedulingPublisher` - The Umbraco instance usually used for backoffice access, responsible for running scheduled tasks. -* `Subscriber` - A scalable instance that subscribes to content updates from the SchedulingPublisher server, not recommended to be used for backoffice access. - -{% hint style="info" %} -These new terms replace 'Master and Replica', in Umbraco versions 7 and 8. -{% endhint %} - -## Explicit SchedulingPublisher server - -It is recommended to configure an explicit SchedulingPublisher server since this reduces the amount of complexity that the election process performs. - -The first thing to do is create a couple of small classes that implement `IServerRoleAccessor` one for each of the different server roles: - -```csharp -public class SchedulingPublisherServerRoleAccessor : IServerRoleAccessor -{ - public ServerRole CurrentServerRole => ServerRole.SchedulingPublisher; -} - -public class SubscriberServerRoleAccessor : IServerRoleAccessor -{ - public ServerRole CurrentServerRole => ServerRole.Subscriber; -} -``` - -then you'll need to replace the default `IServerRoleAccessor` for the your custom registrars. You'll can do this by using the `SetServerRegistrar()` extension method on `IUmbracoBuilder` from a [Composer](../../../../implementation/composing.md). - -```csharp -// This should be executed on your single `SchedulingPublisher` server -builder.SetServerRegistrar(); - -// This should be executed on your `Subscriber` servers -builder.SetServerRegistrar(); -``` - -Now that your subscriber servers are using your custom `SubscriberServerRoleAccessor` class, they will always be deemed 'Subscriber' servers and will not attempt to run the automatic server role election process or task scheduling. - -By setting your SchedulingPublisher server to use your custom `SchedulingPublisherServerRoleAccessor` class, it will always be deemed the 'SchedulingPublisher' and will always be the one that executes all task scheduling. - -## Subscriber servers - Read-only database access - -{% hint style="info" %} -This description pertains only to Umbraco database tables -{% endhint %} - -In some cases infrastructure admins will not want their front-end servers to have write access to the database. By default front-end servers will require write full access to the following tables: - -* `umbracoServer` -* `umbracoNode` - -This is because by default each server will inform the database that they are active and more importantly it is used for task scheduling. Only a single server can execute task scheduling and these tables are used for servers to use a server role election process without the need for any configuration. So in the case that a subscriber server becomes the SchedulingPublisher task scheduler, **it will require write access to all of the Umbraco tables**. - -In order to have read-only database access configured for your front-end servers, you need to implement the [Explicit SchedulingPublisher server](flexible-advanced.md#explicit-schedulingpublisher-server) configuration mentioned above. - -Now that your subscriber servers are using your custom `SubscriberServerRoleAccessor` class, they will always be deemed 'Subscriber' servers and will not attempt to run the automatic server role election process or task scheduling. Because you are no longer using the default `ElectedServerRoleAccessor` they will not try to ping the umbracoServer table. - -{% hint style="info" %} -If using [SqlMainDomLock](azure-web-apps.md#appdomain-synchronization) on Azure WebApps then write-permissions are required for the following tables for all server roles including 'Subscriber'. - -* `umbracoLock` -* `umbracoKeyValue` - -SQL Server Replica databases cannot be used as they are read-only without replacing the default MainDomLock with a custom provider. -{% endhint %} - -## Controlling how often the load balancing instructions from the database are processed and pruned - -The configurations can be adjusted to control how often the load balancing instructions from the database are processed and pruned. - -Below is shown how to do this from a JSON configuration source. - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "DatabaseServerMessenger": { - "MaxProcessingInstructionCount": 1000, - "TimeBetweenPruneOperations": "00:01:00", - "TimeBetweenSyncOperations": "00:00:05", - "TimeToRetainInstructions": "2.00:00:00" - } - } - } - } -} -``` - -Options: - -* `TimeToRetainInstructions` - The timespan to keep instructions in the database; records older than this number will be pruned. -* `MaxProcessingInstructionCount` - The maximum number of instructions that can be processed at startup; otherwise the server cold-boots (rebuilds its caches) -* `TimeBetweenSyncOperations` - The timespan to wait between each sync operations -* `TimeBetweenPruneOperations` - The timespan to wait between each prune operation - -These setting would normally be applied to all environments as they are added to the global app settings. If you need these settings to be environment specific, we recommend using [environment specific `appSetting` files](../../../../reference/configuration/#managing-configuration). diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-scheduler-v9.png b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-scheduler-v9.png deleted file mode 100644 index 1b36ee80b84..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-scheduler-v9.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-scheduler.png b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-scheduler.png deleted file mode 100644 index 010ecfef78e..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-scheduler.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-v9.png b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-v9.png deleted file mode 100644 index e6b6d662975..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing-v9.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing.png b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing.png deleted file mode 100644 index f056aabb13a..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/images/flexible-load-balancing.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/logging.md b/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/logging.md deleted file mode 100644 index 2704a9d3142..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/load-balancing/logging.md +++ /dev/null @@ -1,7 +0,0 @@ -# Logging with load balancing - -Umbraco v8+ uses Serilog for logging. When load balancing Umbraco consideration should be given as to how the log files from each server will be accessed. - -There are many Serilog Sinks available. One of these may be appropriate to store logs for all servers in a central repository such as Azure Application Insights or Elmah.io. - -For more information, see [SeriLog Provided Sinks](https://github.com/serilog/serilog/wiki/Provided-Sinks). diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/permissions.md b/10/umbraco-cms/fundamentals/setup/server-setup/permissions.md deleted file mode 100644 index e1f3a915293..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/permissions.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -meta.Title: "Umbraco file and folder permissions" -description: "Information on file and folder permissions required for Umbraco sites" ---- - -# File and folder permissions - -{% hint style="info" %} -To ensure a stable and smoothly running Umbraco installation, these permissions need to be set correctly. These permissions should be set up before or during the installation of Umbraco. - -The main account that requires 'modify' file permissions to be set on the folders below, is the account used start Umbraco. If Umbraco is hosted in IIS this will be the Application Pool Identity for the IIS website. Usually IIS APPPOOL\appPoolName or a specific local account or in some circumstances Network Service. If in doubt, ask your server admin / hosting company. Additionally, the Internet User (IUSR) account and IIS_IUSRS account only require 'read only' access to the site's folders. - -Generally, when developing locally with Visual Studio or Rider, permissions do not need to be strictly applied. -{% endhint %} - -{% hint style="info" %} -If you have any specific static files/media items/etc, you should add the appropriate permissions accordingly. - -The permissions documentation should allow you to run a plain Umbraco install successfully. -{% endhint %} - -|File / folder |Permission |Comment | -|--------------------------|-----------------------|-----------------------------------------------------| -|`/appSettings*.json` |Modify / Full control |Only needed for setting database and a global identifier during installation. So can be set to read-only afterwards for enhanced security.| -|`/App_Plugins` |Modify / Full control |Should always have modify rights as the folder and its files are used by packages. Not part of your project by default.| -|`/umbraco` |Modify / Full control |Should always have modify rights as the folder and its files are used for cache and storage.| -|`/Views` |Modify / Full control |Should always have modify rights as the folder and its files are used for Templates, Partial views, and Macro files.| -|`/wwwroot/css` |Modify / Full control |Should always have modify rights as the folder and its files are used for CSS files.| -|`/wwwroot/media` |Modify / Full control |Should always have modify rights as the folder and its files are used for Media files uploaded via the Umbraco CMS backoffice.| -|`/wwwroot/scripts` |Modify / Full control |Should always have modify rights as the folder and its files are used for script files.| diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/running-umbraco-in-docker.md b/10/umbraco-cms/fundamentals/setup/server-setup/running-umbraco-in-docker.md deleted file mode 100644 index b72e2fe7d74..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/running-umbraco-in-docker.md +++ /dev/null @@ -1,99 +0,0 @@ -# Running Umbraco in Docker - -Exactly how you choose to compose your Dockerfile will depend on your project specific needs. This section is not intended as a comprehensive guide, rather as an overview of topics to be aware of when hosting in Docker. - -## What is Docker - -Docker is a platform for developing, shipping, and running applications in containers. Multiple services exist for hosting these containers. For more information, refer to the [official Docker Documentation](https://docs.docker.com/) - -## The Docker file system - -By default, files created inside a container are written to an ephemeral, writable container layer.\ -This means that the files don't persist when the container is removed, and it's challenging to get files out of the container. Additionally, this writable layer is not suitable for performance-critical data processing. - -This has implications when running Umbraco in Docker. - -For more information, refer to the [Docker documentation on storage](https://docs.docker.com/engine/storage/). - -### General file system consideration - -In general, when working with files and Docker you work in a "push" fashion with read-only layers. When you build, you take all your files and "push" them into this read-only layer. - -This means that you should avoid making files on the fly, and instead rely on building your image. - -In an Umbraco context, this means you should not create or edit template, script or stylesheet files via the backoffice. These should be deployed as part of your web application and not managed via Umbraco. - -Similarly, you shouldn't use InMemory modelsbuilder, since that also relies on creating files on the disk. While this is not a hard requirement, it doesn't provide any value unless you are live editing your site. - -Instead, configure models builder to use "source code" mode in development, and "none" in production, as [described when using runtime modes](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes). - -### Logs - -Umbraco writes logs to the `/umbraco/Logs/` directory. Due to the performance implications of writing to a writable layer,\ -and the limited size, it is recommended to mount a volume to this directory. - -### Data - -The `/umbraco/Data/` directory is used to store temporary files, such as file uploads. Considering the limitations of the writable layer, you should also mount a volume to this directory. - -### Media - -It's recommended to not store media in the writable layer. This is for similar performance reasons as logs,\ -but also for practical hosting reasons. You likely want to persist media files between containers. - -One solution is to use bind mounts. The ideal setup, though, is to store the media and ImageSharp cache externally. For more information, refer to the [Azure Blob Storage documentation](https://docs.umbraco.com/umbraco-cms/extending/filesystemproviders/azure-blob-storage). - -### Required files - -Your solution may require some specific files to run, such as license files. You will need to pass these files into the container at build time, or mount them externally. - -## HTTPS - -When running websites in Docker, it's common to do so behind a reverse proxy or load balancer.\ -In these scenarios you will likely handle SSL termination at the reverse proxy. This means that Umbraco will not be aware of the SSL termination, and will complain about not using HTTPS. - -Umbraco checks for HTTPS in two locations: - -1. The `HstsCheck` health check - This will result in a failed healthcheck. -2. The `UseHttpsValidator` - This will result in a build error, if Production runtime mode is used. - -To avoid these checks failing, you can remove them in your project. - -### Health Check - -The health check must be removed via configuration, through the `appsettings.json` file, environment variables, or similar. For more information see the [Health Check documentation](../../../reference/configuration/healthchecks.md). - -The `HstsCheck` key is `E2048C48-21C5-4BE1-A80B-8062162DF124` so the appsettings will look something like: - -```json - "Umbraco": { - "CMS": { - "HealthChecks" : { - "DisabledChecks": [ - { - "Id": "E2048C48-21C5-4BE1-A80B-8062162DF124" - } - ] - }, - {...} -``` - -### Runtime mode validator - -The `UseHttpsValidator` must be removed through code For more information see the [Runtime mode documentation](runtime-modes.md). - -The code to remove the validator can look something like: - -```c# -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Infrastructure.Runtime.RuntimeModeValidators; - -namespace MySite; - -public class DockerChecksRemover : IComposer -{ - public void Compose(IUmbracoBuilder builder) - => builder.RuntimeModeValidators().Remove(); -} - -``` diff --git a/10/umbraco-cms/fundamentals/setup/server-setup/runtime-modes.md b/10/umbraco-cms/fundamentals/setup/server-setup/runtime-modes.md deleted file mode 100644 index 8b8265959fa..00000000000 --- a/10/umbraco-cms/fundamentals/setup/server-setup/runtime-modes.md +++ /dev/null @@ -1,160 +0,0 @@ -# Runtime Modes - -_This section describes how to use the runtime mode setting to optimize Umbraco for the best development experience or optimal production environment._ - -## Configuring the runtime mode - -You can configure the runtime mode to optimize Umbraco for different development experiences and environments by setting `Umbraco:CMS:Runtime:Mode` to one of the available modes: - -* `BackofficeDevelopment` (default) -* `Development` -* `Production` - -This can be done via the `appsettings.json` file, environment variables, or any other .NET configuration provider (like Azure Key Vault/App Configuration). Although this setting affects how Umbraco behaves at runtime, some modes have prerequisites on how the project is built/published. Make sure to read the descriptions of each mode before changing this setting from the default `BackofficeDevelopment` mode, as incorrect configuration can result in your application not starting (by throwing a `BootFailedException`). - -## BackofficeDevelopment mode - -The `BackofficeDevelopment` mode is the default behavior for Umbraco: it does not optimize Umbraco for any specific environment and does not have any prerequisites. This mode allows for rapid development (without having to recompile/rebuild your project), including all development from within the backoffice. - -## Development mode - -The `Development` mode can be used when you're developing from an IDE (like Visual Studio, VS Code, or Rider) or the dotnet CLI (e.g. using `dotnet watch`). It is a recommended prerequisite if you want to use the `Production` mode in your production environment. - -This mode disables in-memory ModelsBuilder generation and validates the following setting: - -* `Umbraco:CMS:ModelsBuilder:ModelsMode` is not set to `InMemoryAuto`. - -If you want to use the generated models, use `SourceCodeAuto` or `SourceCodeManual`, which requires manually recompiling the project after the models have changed (e.g. after updating Document Types, Media Types, Member Types, or Data Types). Razor views (`cshtml` files) will still be automatically compiled at runtime, allowing you to quickly iterate on the rendered output from templates, (macro) partial views, and view components. - -The recommended approach to enable `Development` mode is to update the `appsettings.json` file with the following settings: - -```json -{ - "Umbraco": { - "CMS": { - "Runtime": { - "Mode" : "Development" - }, - "ModelsBuilder":{ - "ModelsMode": "SourceCodeAuto" - } - } - } -} -``` - -Ensure your models are generated by running Umbraco and navigating to **Settings** > **Models Builder** > **Generate models**. You can remove the following properties from your `csproj` project file to enable the compilation of Razor views (which also ensures your views do not contain compilation errors and is a prerequisite for enabling `Production` mode): - -```xml -false -false -``` - -Fix any compilation errors you might get after this, e.g. if you accidentally referenced deleted models or properties. Running the application will still show the rendered content and you're now ready to optionally enable `Production` mode on your production environment. - -{% hint style="info" %} -Ensure you have the `true` property set in your `csproj` project file, so Razor views are always copied to the publish directory. This is required by the CMS to display the contents in the backoffice, for Forms to lookup custom theme views and for Deploy to be able to compare schemas (otherwise you'll get schema mismatches). -{% endhint %} - -## Production mode - -Use `Production` mode to ensure your production environment is running optimally by disabling development features and validating whether specific settings are configured to their recommended production values. - -This mode disables both in-memory ModelsBuilder generation (see [Development mode](runtime-modes.md#development-mode)) and Razor (cshtml) runtime compilation. Production mode requires you to compile your views at build/publish time and enforces the following settings for optimal performance/security: - -* The application is built/published in Release mode (with JIT optimization enabled), e.g. using `dotnet publish --configuration Release`; -* `Umbraco:CMS:WebRouting:UmbracoApplicationUrl` is set to a valid URL; -* `Umbraco:CMS:Global:UseHttps` is enabled; -* `Umbraco:CMS:RuntimeMinification:CacheBuster` is set to a fixed cache buster like `Version` or `AppDomain`; -* `Umbraco:CMS:ModelsBuilder:ModelsMode` is set to `Nothing`. - -{% hint style="info" %} -To compile your views at build/publish time, remove the `` and `` properties from your project file (see the [Development mode](runtime-modes.md#development-mode) section). If you don't, Umbraco can't find the templates and will return 404 (Page Not Found) errors. -{% endhint %} - -The recommended approach to enable `Production` mode is to update the `appsettings.Production.json` file (or create one) with the following settings: - -```json -{ - "Umbraco": { - "CMS": { - "Runtime": { - "Mode": "Production" - }, - "Global": { - "UseHttps": true - }, - "ModelsBuilder": { - "ModelsMode": "Nothing" - }, - "WebRouting": { - "UmbracoApplicationUrl": "https:///" - } - } - } -} -``` - -Although you can still edit document types and views (if not running from the published output), changes won't be picked up until you've rebuilt your project or republished the application. - -{% hint style="info" %} -Models won't be generated by ModelsBuilder (because the mode is set to `Nothing`), requiring you to do all your changes while in `Development` mode.\ -\ -As Models Builder are set to `Nothing`, the Models Builder dashboard is disabled in the backoffice of live environment. - -\ -\ -Also, templates cannot be edited on live environment as runtime compilation is not enabled and is set to Production. - - -{% endhint %} - -Also ensure the `UmbracoApplicationUrl` is updated to the primary URL of your production environment, as this is used when sending emails (password reset, notifications, health check results, etc.) and the keep-alive task. - -## Customize/extend runtime mode validation - -Validation of the above-mentioned settings is done when determining the runtime level during startup using the new `IRuntimeModeValidationService` and when it fails, causes a `BootFailedException` to be thrown. The default implementation gets all registered `IRuntimeModeValidators` to do the validation, making it possible to remove default checks and/or add your own (inherit from `RuntimeModeProductionValidatorBase`, if you only want to validate against the production runtime mode). The following validators are added by default: - -* `JITOptimizerValidator` - Ensure the application is built/published in Release mode (with JIT optimization enabled) when in production runtime mode, e.g. using `dotnet publish --configuration Release`; -* `UmbracoApplicationUrlValidator` - ensure `Umbraco:CMS:WebRouting:UmbracoApplicationUrl` is configured when in production runtime mode; -* `UseHttpsValidator` - ensure `Umbraco:CMS:Global:UseHttps` is enabled when in production runtime mode; -* `RuntimeMinificationValidator` - ensure `Umbraco:CMS:RuntimeMinification:CacheBuster` is set to a fixed cache buster like `Version` or `AppDomain` when in production runtime mode; -* `ModelsBuilderModeValidator` - ensure `Umbraco:CMS:ModelsBuilder:ModelsMode` is not set to `InMemoryAuto` when in development runtime mode and set to `Nothing` when in production runtime mode. - -The following example removes the default `UmbracoApplicationUrlValidator` and adds a new custom `DisableElectionForSingleServerValidator`: - -```csharp -using System.Diagnostics.CodeAnalysis; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Infrastructure.Runtime; -using Umbraco.Cms.Infrastructure.Runtime.RuntimeModeValidators; - -public class RuntimeModeValidatorComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - => builder.RuntimeModeValidators() - .Remove() - .Add(); -} - -public class DisableElectionForSingleServerValidator : IRuntimeModeValidator -{ - private readonly IOptionsMonitor _globalSettings; - - public DisableElectionForSingleServerValidator(IOptionsMonitor globalSettings) => _globalSettings = globalSettings; - - public bool Validate(RuntimeMode runtimeMode, [NotNullWhen(false)] out string? validationErrorMessage) - { - if (runtimeMode == RuntimeMode.Production && _globalSettings.CurrentValue.DisableElectionForSingleServer == false) - { - validationErrorMessage = "Disable primary server election (and support for load balancing) to improve startup performance."; - return false; - } - - validationErrorMessage = null; - return true; - } -} -``` diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/README.md b/10/umbraco-cms/fundamentals/setup/upgrading/README.md deleted file mode 100644 index bc570f09120..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/README.md +++ /dev/null @@ -1,171 +0,0 @@ -# Upgrade your project - -_This is the guide for upgrading existing installations in general._ - -In this article, you will find everything you need to upgrade your Umbraco CMS project. - -You will find instructions on how to upgrade to a new minor or major version as well as how to run upgrades unattended. - -* [Before you upgrade](./#before-you-upgrade) -* [Upgrade to a new Major](./#upgrade-to-a-new-major) -* [Upgrade to a new Minor](./#upgrade-to-a-new-minor) -* [Run an unattended upgrade](./#run-an-unattended-upgrade) - -## Before you upgrade - -The following lists a few things to be aware of before initiating an upgrade of your Umbraco CMS project. - -* Sometimes there are exceptions to general upgrade guidelines. These are listed in the [**version-specific guide**](version-specific/). Be sure to read this article before moving on. -* Check if your setup meets the [requirements](../requirements.md) for the new versions you will be upgrading your project to. -* Things may go wrong for different reasons. Be sure to **ALWAYS** keep a backup of both your site's files and the database. This way you can always return to a version that you know works. -* Before upgrading to a new major version, check if the packages you're using are compatible with the version you're upgrading to. On the package's download page, in the **Project compatibility** area, click **View details** to check version-specific compatibility. - -{% hint style="info" %} -It is necessary to run the upgrade installer on each environment of your Umbraco site. This means that you need to repeat the steps below on each of your environments in order to complete the upgrade. -{% endhint %} - -## Legacy Umbraco - -The steps outlined in this article apply to modern Umbraco from version 10 and later versions. - -Are you upgrading to a minor for Umbraco 6, 7, or 8? You can find the appropriate guide below: - -{% content-ref url="version-specific/minor-upgrades-for-umbraco-8.md" %} -[minor-upgrades-for-umbraco-8.md](version-specific/minor-upgrades-for-umbraco-8.md) -{% endcontent-ref %} - -{% content-ref url="version-specific/minor-upgrades-for-umbraco-7.md" %} -[minor-upgrades-for-umbraco-7.md](version-specific/minor-upgrades-for-umbraco-7.md) -{% endcontent-ref %} - -## Upgrade to a new Major - -You can upgrade to a new major of Umbraco CMS directly by using NuGet. - -{% hint style="warning" %} -Switching to a new major of Umbraco CMS also means switching to a new .NET version. You need to make sure that any packages used on your site are compatible with this version before upgrading. - -The package compatibility can be checked on the package's download page. Locate the **Project compatibility** area and select **View details** to check version-specific compatibility. -{% endhint %} - -### Choose the correct .NET version - -Use the table below to determine which .NET version to upgrade to when going through the steps below. - -| CMS version | .NET version | -| ----------- | ------------ | -| 12 | 7.0 | -| 11 | 7.0 | -| 10 | 6.0.5 | - -### Upgrade your project using Visual Studio - -It's recommended that you upgrade the site offline and test the upgrade fully before deploying it to the production environment. - -1. Stop your site in IIS to prevent any changes from being made while you are upgrading. -2. Open your Umbraco project in Visual Studio. -3. Right-click on the project name in the Solution Explorer and select **Properties**. -4. Select the **.NET** version from the **Target Framework** drop-down. -5. Go to **Tools** > **NuGet Package Manager** > **Manage NuGet Packages for Solution...** -6. Go to the **Installed** tab in the NuGet Package manager. -7. Upgrade **Umbraco.Cms**. - - a. Select the correct version from the **Version** drop-down. - - b. Click **Install** to upgrade your project. - -{% hint style="info" %} -If you have other packages installed such as Umbraco Forms, then before upgrading **Umbraco.CMS** you will need to upgrade the packages first. Consult the [version specific upgrade notes for Umbraco Forms](https://docs.umbraco.com/umbraco-forms/upgrading/version-specific) if relevant. -{% endhint %} - -8. Make sure that your connection string has `TrustServerCertificate=True` in order to complete successfully the upgrade: - -```csharp -"ConnectionStrings": { - "umbracoDbDSN": "Server=YourLocalSQLServerHere;Database=NameOfYourDatabaseHere;User Id=NameOfYourUserHere;Password=YourPasswordHere;TrustServerCertificate=True" -} -``` - -9. Restart your site in IIS, build, and run your project to finish the installation. - -{% hint style="warning" %} -If your database experiences timeout issues after an upgrade, it might be due to [ASP.NET Core Module's](https://learn.microsoft.com/en-us/aspnet/core/test/troubleshoot-azure-iis?#default-startup-limits) 'startupTimeLimit' configuration. - -To fix the issue, try increasing the [`startupTimeLimit`](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/web-config?) in the `web.config` file. Additionally, you can set the [`Connection Timeout`](https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.connectiontimeout?) value in the [`ConnectionString`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnection.connectionstring?) in the `appsettings.json` file. -{% endhint %} - -## Upgrade to a new Minor - -NuGet installs the latest version of the package when you use the `dotnet add package` command unless you specify a package version: - -`dotnet add package Umbraco.Cms --version ` - -Add a package reference to your project by executing the `dotnet add package Umbraco.Cms` command in the directory that contains your project file. - -Run `dotnet restore` to install the package. - -{% hint style="warning" %} -For v9: If you are using SQL CE in your project you will need to run `dotnet add package Umbraco.Cms.SqlCe --version ` before running the `dotnet restore` command. From v10, SQL CE has been replaced with SQLite so a `dotnet restore` should be sufficient. If this is not working then you will need to run `dotnet add package Umbraco.Cms.Persistence.Sqlite --version ` and then `dotnet restore`. -{% endhint %} - -When the command completes, open the **.csproj** file to make sure the package reference was updated: - -```xml - - - -``` - -## Run an unattended upgrade - -When upgrading your Umbraco project, it is possible to enable the upgrade to run unattended. This means that you will not need to run through the installation wizard when upgrading. - -Below you will find the steps you need to take in order to upgrade your project unattended. - -{% hint style="info" %} -Are you running a load balanced setup with multiple servers and environments? - -Check out the section about [Unattended upgrades in a load balanced setup](./#unattended-upgrades-in-a-load-balanced-setup). -{% endhint %} - -### Enable the unattended upgrade feature - -1. Add the `Umbraco:Cms:Unattended:UpgradeUnattended` configuration key. -2. Set the value of the key to `true`. - -{% code title="appsettings.json" %} -```json -{ - "Umbraco": { - "CMS": { - "Unattended": { - "UpgradeUnattended": true - } - } - } -} -``` -{% endcode %} - -### Run the upgrade - -With the correct configuration applied, the project will be upgraded on the next boot. - -#### Boot order - -The Runtime level will use `Run` instead of `Upgrade` to allow the website to continue to boot up directly after the migration is run. This happens instead of initiating the otherwise required restart. - -{% hint style="info" %} -The upgrade is run after Composers but before Components and the `UmbracoApplicationStartingNotification`. This is because the migration requires services that are registered in Composers and Components require that Umbraco and the database are ready. -{% endhint %} - -### Unattended upgrades in a load balanced setup - -Follow the steps outlined below to use unattended upgrades in a load balanced setup. - -1. Upgrade Umbraco via NuGet ([see instructions above](./#upgrade-to-a-new-major)) -2. Deploy to all environments. -3. Set the `Umbraco:CMS:Unattended:UpgradeUnattended` configuration key to `true` for **the Main server only**. -4. Boot the Main server and the upgrade will run automatically. -5. Wait for the upgrade to complete. -6. Boot the Read-Only servers and make sure they do not show the “upgrade required” screen. diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (1) (1).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (1).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (2).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (2).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (3).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (3).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2) (1).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2) (2).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1 (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1.png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/content-on-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (1) (1).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (1).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (2).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (2).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (3).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (3).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2) (1).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2) (2).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site.png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/fresh-8_1-site.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (1) (1).png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (1).png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (2).png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog.png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-overwrite-dialog.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (1) (1).png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (1).png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (2).png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite.png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/nuget-upgrade-overwrite.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (1) (1).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (1).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (2).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (2).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (3).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (3).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2) (1).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2) (2).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version.png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/set-umbraco-version.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (1) (1).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (1).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (2).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (3).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (3).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2) (1).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2) (2).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1 (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1.png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrade-to-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (1) (1).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (1).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (2).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (2).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (3).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (3).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2) (1).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2) (2).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14 (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14.png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/upgrading-7_14.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (1) (1).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (1).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (2).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (2).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (3).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (3).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1) (3).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2) (1).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2) (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2) (2).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2) (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content.png b/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content.png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/images/v7-content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/README.md b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/README.md deleted file mode 100644 index 474752954cc..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/README.md +++ /dev/null @@ -1,787 +0,0 @@ ---- -description: >- - This document covers specific upgrade steps if a version requires them. Most - versions do not require specific upgrade steps and you will be able to upgrade - directly from your current version. ---- - -# Version Specific Upgrades - -Use the information below to learn about any potential breaking changes and common pitfalls when upgrading your Umbraco CMS project. - -If any specific steps are involved with upgrading to a specific version, they will be listed below. - -Use the [general upgrade guide](../) to complete the upgrade of your project. - -## Breaking changes - -
- -Umbraco 10 - -[**Update 'diff' from 3.5.0 to 5.0.0**](https://github.com/umbraco/Umbraco-CMS/issues/12337) - -The `diff` library used in the Backoffice client has been updated and introduces a breaking change since the exposed global object has been renamed from `JsDiff` to `Diff`. - -[**Content Schedule performance**](https://github.com/umbraco/Umbraco-CMS/pull/11398) - -Removes mutable ContentSchedule property from `IContent/Content` to `read/write` content schedules. - -Use _IContentService.GetContentScheduleByContentId && IContentService.PersistContentSchedule_ or the optional _contentSchedule parameter_ on _IContentService.Save_ instead. - -[**Removed redundant event handling code**](https://github.com/umbraco/Umbraco-CMS/pull/11842) - -* Removed public methods: `PublishedSnapshotServiceEventHandler.Dispose`, `PublishedSnapshotServiceEventHandler.Dispose(bool)`, and `.PublishedSnapshotServiceEventHandler.Initialize`. -* Removed public `ctor`. - -[**Scope provider cleanup**](https://github.com/umbraco/Umbraco-CMS/pull/11859) - -* Some public classes in the `Cms.Core.Services` namespace have moved assembly from **`Umbraco.Cms.Infrastructure`** to **`Umbraco.Cms.Core`**. -* These same public classes have changed namespace from **`Umbraco.Cms.Core.Services.Implement`** to **`Umbraco.Cms.Core.Services`**. - -[**Update to NPoco5**](https://github.com/umbraco/Umbraco-CMS/pull/11880) - -NPoco types and interfaces are part of our public interface which means that this upgrade imposes breaking changes. - -[**SQLite support**](https://github.com/umbraco/Umbraco-CMS/pull/11922) - -* Removed support for Microsoft SQL Server Compact (SQL CE). -* Removed `ReadLock` and `WriteLock` methods from `ISqlSyntaxProvider` interface. Use `IDistributedLockingMechanism` (or IScope which delegates to `IDistributedLockingMechanism`) instead. -* Constants for SQL Server provider name moved+consolidated from `Core.Constants.DatabaseProviders` and `Core.Constants.-DbProviderNames` to `Umbraco.Cms.Persistence.SqlServer.Constants` -* Some SQL Server related services moved from the `Umbraco.Infrastructure` project to the new `Umbraco.Cms.Persistence`. -* SqlServer project with altered namespaces e.g. `SqlServerSyntaxProvider`, `SqlServerBulkSqlInsertProvider`, `SqlServerDatabaseCreator`. - -**Added the following methods/properties to ISqlSyntaxProvider. These must be implemented in any downstream implementation e.g:** - -* `ISqlSyntaxProvider.HandleCreateTable(IDatabase,TableDefinition,Boolean)` -* `ISqlSyntaxProvider.GetFieldNameForUpdate()` -* `ISqlSyntaxProvider.GetColumn(DatabaseType,String,String,String,String,Boolean)` -* `ISqlSyntaxProvider.InsertForUpdateHint(Sql)` -* `ISqlSyntaxProvider.AppendForUpdateHint(Sql)` -* `ISqlSyntaxProvider.LeftJoinWithNestedJoin(Sql,Func,String)` - -[**Update to ImageSharp v2**](https://github.com/umbraco/Umbraco-CMS/pull/12185) - -**Update dependency versions**: - -* `SixLabors.ImageSharp` from 1.0.4 to 2.1.1 -* `SixLabors.ImageSharp.Web` from 1.0.5 to 2.0.0 - -Renamed the `CachedNameLength` property to `CacheHashLength` on **ImagingCacheSettings**. - -Moved **ImageSharpImageUrlGenerator** from project `Umbraco.Infrastructure` to `Umbraco.Web.Common` and updated the corresponding namespace and DI registration (from `AddCoreInitialServices()` to `AddUmbracoImageSharp()`); - -Moved **ImageSharp** configuration from the `AddUmbracoImageSharp()` extension method into separate `IConfigureOptions<>` implementations: - -* The middleware is configured in ConfigureImageSharpMiddlewareOptions (which also replaces ImageSharpConfigurationOptions that previously only set the default ImageSharp configuration); -* The default physical cache is configured in ConfigurePhysicalFileSystemCacheOptions. - -[**Migrate Member properties to columns on the Member table**](https://github.com/umbraco/Umbraco-CMS/pull/12205) - -This is breaking because it is no longer possible to access the properties listed below through the _IMember.Properties_ collection. You must now access them through their specific properties that is _IMember.IsLockedOut_. - -* `umbracoMemberFailedPasswordAttempts` -* `umbracoMemberApproved` -* `umbracoMemberLockedOut` -* `umbracoMemberLastLockoutDate` -* `umbracoMemberLastLogin` -* `umbracoMemberLastPasswordChangeDate` - -Additionally, when previously you resolved a Member as published content, all the default properties would be there twice. For instance, `IsLockedOut` would be there both as a property with the alias `umbracoMemberLockedOut` and with the alias `IsLockedOut`. Now it'll only be there once, with the alias being the name of the property, so `IsLockedOut` in this instance. - -Lastly the nullable dates on a user, i.e. `LastLoginLate` will now be null instead of `DateTime.MinValue` when getting a user with the UserService. - -[**Update examine to version 3**](https://github.com/umbraco/Umbraco-CMS/pull/12307) - -**Examine 3 breaking changes:** - -* `ValueSet` immutable. -* `ValueSetValidationResult` is renamed to `ValueSetValidationStatus` and `ValueSetValidationResult` is now a type. - -[**Async support for content finders**](https://github.com/umbraco/Umbraco-CMS/pull/12340) - -```CSharp -bool TryFindContent(IPublishedRequestBuilder request); -``` - -Has changed to: - -```CSharp -Task TryFindContent(IPublishedRequestBuilder request); -``` - -[**Improve redirect Content finder scalability**](https://github.com/umbraco/Umbraco-CMS/pull/12341) - -* Added more methods to `IRedirectUrlRepository` and `IRedirectUrlService.cs`. - -[**Fix Block List settings exception and optimize PVCs**](https://github.com/umbraco/Umbraco-CMS/pull/12342) - -* Added a new method on `IPublishedModelFactory`: Type `GetModelType(string? alias)`; -* The generic types of a `BlockListItem`instance in the`BlockListModel`returned by`BlockListPropertyValueConverter`is now determined by calling this new method, which can be different and cause a`ModelBindingException\` in your views. - -[**Async tree search**](https://github.com/umbraco/Umbraco-CMS/pull/12344) - -```CSharp -IEnumerable Search(string query, int pageSize, long pageIndex, out long totalFound, string? searchFrom -= null) -``` - -Has changed to: - -```CSharp -Task SearchAsync(string query, int pageSize, long pageIndex, string? searchFrom = null); -``` - -[**Moved StackQueue to correct namespace**](https://github.com/umbraco/Umbraco-CMS/pull/12347) - -StackQueue has been moved from `Umbraco.Core.Collections` to the `Umbraco.Cms.Core.Collections` namespace. - -**Globalsetting SqlWriteLockTimeOut has been removed** - -This setting has been superseded by `DistributedLockingWriteLockDefaultTimeout`. - -
- -## Release notes - -You can find a list of all the released Umbraco versions on [Our Umbraco](https://our.umbraco.com/download/releases/) website. When you visit Our Umbraco website, click on the version number to view the changes made in that specific version. - -## Find your upgrade path - -Are you looking to upgrade an Umbraco Cloud project from 9 to 10? Follow the guide [Upgrading your project from Umbraco 9 to 10](https://docs.umbraco.com/umbraco-cloud/optimize-and-maintain-your-site/manage-product-upgrades/product-upgrades/major-upgrades) instead, as it requires a few steps specific to Umbraco Cloud. - -
- -10.latest to version 11 - -It might be necessary to delete all of the `bin` and `obj` directories in each of the projects of your solution. It has been observed that Visual Studio's "Clean Solution" option is sometimes not enough. - -You can upgrade from Umbraco 10 to Umbraco 11 directly. However, as Umbraco 11 has reached end-of-life, it is recommended to upgrade to a [Long-term Support (LTS) major](https://umbraco.com/products/knowledge-center/long-term-support-and-end-of-life/) version. - -
- -
- -9.latest to 10 - -**Important**: .NET version 6.0.5 is the minimum required version for Umbraco 10 to be able to run. You can check with `dotnet --list-sdks` what your latest installed Software Development Kit (SDK) version is. SDK version 6.0.300 is the one that includes .NET 6.0.5. At the time of writing, .NET 6.0.6 is out with an SDK version of 6.0.301. - -Watch the ['Upgrading from Umbraco 9 to Umbraco 10 video tutorial'](https://www.youtube.com/watch?v=075H\_ekJBKI\&ab\_channel=UmbracoLearningBase) for a complete walk-through of all the steps. - -The upgrade path between Umbraco 9 and Umbraco 10 can be done directly by upgrading your project using NuGet. You will need to ensure the packages you are using are available in Umbraco 10. - -**SQL CE is no longer a supported database engine** - -There is no official migration path from SQL CE to another database engine. - -The following options may suit your needs: - -* Follow a community guide to migrate from a SQL CE database to SQL Server, like the [article by Jan Reilink](https://www.saotn.org/convert-sqlce-database-to-sql-server/) -* Setup a new database for v10 and use [uSync](https://jumoo.co.uk/usync/) to transfer document types and content across. -* Setup a new database for v10 and use a premium tool such as [redgate SQL Data Compare](https://www.red-gate.com/products/sql-development/sql-data-compare/) to copy database contents across. -* Setup a new database for v10 and use a premium tool such as [Umbraco Deploy](https://umbraco.com/products/umbraco-deploy) to transfer document types and content across. - -**Steps to upgrade using Visual Studio** - -It's recommended that you upgrade the site offline, and test the upgrade fully before deploying it to the production environment. - -1. Stop your site in IIS to prevent any changes being made to the database or filesystem while you are upgrading. -2. Open your Umbraco 9 project in Visual Studio. -3. Right-click on the project name in the Solution Explorer and select **Properties**. -4. Select **.NET 6.0** from the **Target Framework** drop-down. -5. Go to **Tools** > **NuGet Package Manager** > **Manage NuGet Packages for Solution...** -6. Go to the **Installed** tab in the NuGet Package manager. -7. Choose **Umbraco.Cms**. -8. Select **10.0.0** from the **Version** drop-down and click **Install** to upgrade your project to version 10. -9. Update `Program.cs` to the following: - -```csharp -public class Program -{ - public static void Main(string[] args) - => CreateHostBuilder(args) - .Build() - .Run(); - - // The calls to `ConfigureUmbracoDefaults` and `webBuilder.UseStaticWebAssets()` are new. - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureUmbracoDefaults() - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStaticWebAssets(); - webBuilder.UseStartup(); - }); -} -``` - -10. Remove the following files and folders: - * `/wwwroot/umbraco` - * `/umbraco/PartialViewMacros` - * `/umbraco/UmbracoBackOffice` - * `/umbraco/UmbracoInstall` - * `/umbraco/UmbracoWebsite` - * `/umbraco/config/lang` - * `/umbraco/config/appsettings-schema.json` -11. If using Umbraco Forms, update your files and folders according to the [Upgrading - version specific](https://docs.umbraco.com/umbraco-forms/installation/version-specific) for version 10 article. -12. Restart your site in IIS, build and run your project to finish the installation of Umbraco 10. - -To re-enable the appsettings IntelliSense, you must update your schema reference in the `appsettings.json` file and any other `appsettings.{Environment}.json` files from: - -```json -"$schema": "./umbraco/config/appsettings-schema.json", -``` - -To: - -```json -"$schema": "./appsettings-schema.json", -``` - -To upgrade to Umbraco 10, your database needs to be at least on Umbraco 8.18. - -**Upgrade of any publicly hosted environment** - -When the upgrade is completed and tested, and prior to deploying to any publicly accessible environment, you should consider the following: - -1. Ensure you have backups for both the database and the file system. -2. Stop the site so it is not accessible during the upgrade process. -3. Delete the relevant folders from the filesystem prior to deploying: - * `/wwwroot/umbraco` - * `/umbraco/PartialViewMacros` - * `/umbraco/UmbracoBackOffice` - * `/umbraco/UmbracoInstall` - * `/umbraco/UmbracoWebsite` - * `/umbraco/config/lang` - * `/umbraco/config/appsettings-schema.json` -4. If you are using Umbraco Forms, update your files and folders according to the [Upgrading - version specific](https://docs.umbraco.com/umbraco-forms/installation/version-specific) for version 10 article. -5. Deploy the site how you normally would to your public facing environment. -6. Start the site. At this point it will launch and upgrade the database, after which the site should become accessible and your upgrade is complete. -7. Check the logs for any errors which may have occurred during the upgrade process. - -
- -
- -8.latest to 9 - -There is no direct upgrade path from Umbraco 8 to Umbraco 9. It is however possible to migrate from Umbraco 8 sites to Umbraco 9 sites. - -You can reuse your content by restoring your Umbraco 8 database into a new database used for an Umbraco 9 site. - -You need to ensure the packages you are using are available in Umbraco 9, and you will need to reimplement your custom code and templates. - -The direct upgrade path is not possible because the codebase has been fundamentally updated in Umbraco 9. The underlying web framework has been updated from ASP.NET to ASP.NET Core. - -It is not possible to take this step while maintaining full compatibility with Umbraco 8. - -
- -
- -8.0.0 to 8.1.0 - -There are a few breaking changes from 8.0.x to 8.1.0. Make sure to check the [full list](https://github.com/umbraco/Umbraco-CMS/issues?q=is%3Aissue+label%3Arelease%2F8.1.0+is%3Aclosed+label%3Acategory%2Fbreaking). - -**IPublishedContent breaking changes in 8.1.0** - -Due to the [changes in `IPublishedContent`](https://github.com/umbraco/Umbraco-CMS/issues/5170) there are a few steps you will need to take, to make sure that your site works. - -The `IPublishedContent` interface is central to Umbraco, as it represents published content and media items at the rendering layer level. This could be in controllers or views. In other words, it is the interface that is used everywhere when building sites. - -The introduction of multilingual support in version 8 required changes to the interface. For instance, a property value could be obtained with `GetPropertyValue(alias)` in version 7. Version 8 requires a new parameter for culture, and the call thus became `Value(alias, culture)`. - -In the excitement of the version 8 release, we assumed that `IPublishedContent` was "done". By our tests, everything was looking good. However, feedback from early testers showed that the interface was in some places odd or inconsistent or had issues. - -Fixing the bugs is a requirement. Some of the required bug fixes could not be achieved without introducing some breaking changes. - -At that point, we decided to give `IPublishedContent` some love. We fixed the bugs and made it clean, friendly, discoverable, and predictable for the entire life of version 8. - -Breaking changes to such a central interface is not something we take lightly. Even though they do not impact the "concepts" nor require heavy refactoring, they may demand an amount of small fixes here and there. - -The general idea underlying these changes is that: - -* The proper way to retrieve "something" from an `IPublishedContent` instance is always through a method, for example: `Children()`. And, when that method can be multilingual, the method accepts a `culture` parameter, which can be left `null` to get the "current" culture value. -* To reduce the amount of breaking changes, and to simplify things for non-multilingual sites, existing properties such as `document.Name` and `document.Children` (and others) still exist, and return the value for the current culture. In other words, these properties are now implemented as `document.Name => document.Name()` or `document.Children => document.Children()`. - -The rest of this document presents each change in details. - -**More interfaces** - -It was possible to mock and test the `IPublishedContent` interface in version 7. It has been improved in version 8, but it still relies on concrete `PublishedContentType` and `PublishedPropertyType` classes to represent the content types, which complicates things. - -In version 8.1, these two classes are abstracted as `IPublishedContentType` and `IPublishedPropertyType`, thus making `IPublishedContent` easier to mock and test. - -**CHANGE**: This impacts every method accepting or returning a content type. For instance, the signature of most `IPropertyValueConverter` methods changes. References to `PublishedContentType` must be replaced with references to `IPublishedContentType`. - -The following `IPublishedContent` members change: - -**Name** - -The `document.Name` property is complemented by the `document.Name(string culture = null)` extension method. The property returns the name for the current culture. The `document.GetCulture(...).Name` syntax is removed. - -**CHANGE**: Calls to `document.GetCulture(culture).Name` must be replaced with `document.Name(culture)`. - -**UrlSegment** - -The `document.UrlSegment` property is complemented by the `document.UrlSegment(string culture = null)` extension method. The property returns the Url segment for the current culture. The `document.GetCulture(...).UrlSegment` syntax is removed. - -**CHANGE**: Calls to `document.GetCulture(culture).UrlSegment` must be replaced with `document.UrlSegment(culture)`. - -**Culture** - -The `document.GetCulture()` method is removed. The proper way to get a culture date is `document.CultureDate(string culture = null)`. The `document.Cultures` property now returns the invariant culture, for invariant documents. - -**CHANGE**: Calls to `document.GetCulture(culture).Date` must be replaced with `document.CultureDate(culture)`. Calls to `document.Cultures` must take into account the invariant culture. - -**Children** - -The `document.Children` property is complemented by the `document.Children(string culture = null)` extension method which, when a culture is specified always return children available for the specified culture. The property returns the children available for the current culture. - -A new `document.ChildrenForAllCultures` property is introduced, which returns _all_ children, regardless of whether they are available for a culture or not. - -**CHANGE**: Calls to `document.Children` may have to be replaced by `document.ChildrenForAllCultures` depending on if the 8.0.x usage of this was relying on it returning unfiltered/all children regardless of the current routed culture. - -**Url** - -The `document.Url` property is complemented by the `document.Url(string culture = null, UrlMode mode = UrlMode.Auto)` extension method. The `document.GetUrl(...)` and `document.UrlAbsolute()` methods are removed. The `UrlProviderMode` enumeration is renamed `UrlMode`. - -**CHANGE**: Calls to `document.GetUrl(...)` must be replaced with `document.Url(...)`. Calls to `document.UrlAbsolute()` must be replaced with `document.Url(mode: UrlMode.Absolute)`. - -**UmbracoContext** - -Due to the `UrlProviderMode` enumeration being renamed `UrlMode`, the signature of some overloads of the `Url(...)` method has changed. Methods that do not have a mode parameter remain unchanged. - -**CHANGE**: Code such as `context.Url(1234, UrlProviderMode.Absolute)` must become `context.Url(1234, UrlMode.Absolute)`. - -The `UmbracoContext` class gives access to the rendering layer, which is more than a "cache". To reflect this, its `ContentCache` and `MediaCache` properties are renamed `Content` and `Media`. However, the old properties remain as obsolete properties. - -**CHANGE**: None required in 8.1, but code such as `context.ContentCache.GetById(1234)` should eventually be converted to `context.Content.GetById(1234)` as the obsolete properties may be removed in a further release. - -**GetCulture** - -Version 7 had a `document.GetCulture()` method that was deriving a culture from domains configured in the tree. Somehow, that method was lost during version 8 development (issue [#5269](https://github.com/umbraco/Umbraco-CMS/issues/5269)). - -Because that method is useful, especially when building traditional, non-multilingual sites, it has been re-introduced in version 8.1 as `document.GetCultureFromDomains()`. - -**CHANGE**: None. - -**DomainHelper** - -`DomainHelper` has been replaced with a static `DomainUtilities` class. - -**CHANGE**: It is rare that `DomainHelper` is used in code since it only contains one public method but if developers are using this, it can no longer be injected since it's now a static class called `DomainUtilities`. - -**Models Builder** - -If you're using ModelsBuilder in `dll` mode you need to delete the dlls before upgrading. Otherwise, they're going to be wrong and cause your whole site to throw errors. - -If you're using ModelsBuilder in `AppData` mode and you have your generated models in your solution you need to update them after upgrading. `PublishedContentType` will need to be replaced with `IPublishedContentType`. If you have an implementation of the `PropertyValueConverter` class, you need to replace all references to `PublishedPropertyType` with `IPublishedPropertyType` within that class. Only after you do that will your solution build again. - -**AutoMapper** - -Umbraco 8.1 replaces AutoMapper with [UmbracoMapper](../../../../reference/mapping.md). This in itself will not break anything on your site. If you have used AutoMapper in your own code you will have to either include the package yourself or switch your implementation to use UmbracoMapper. - -**Follow the** [**upgrade guide for Umbraco 8**](minor-upgrades-for-umbraco-8.md) **to complete the upgrade** - -
- -
- -7.latest to 8.0.0 - -There is no direct upgrade path from Umbraco 7 to Umbraco 8. It is however possible to migrate content from Umbraco 7 sites to Umbraco 8 sites. We have added content migrations in Umbraco 8.1.0 enabling you to migrate your content from Umbraco 7 to Umbraco 8. - -It is not possible to upgrade an Umbraco 7 site to Umbraco 8 because the codebase has been fundamentally updated in Umbraco 8. A lot of outdated code and technology has been removed and instead new, faster, and more secure technology has been implemented. - -In Umbraco 8 we have added improvements and updated dependencies. We have also done a thorough clean-up to make it simpler for you to work with and extend your Umbraco project. - -[**Migrate your content to Umbraco 8**](migrate-content-to-umbraco-8.md) - -
- -
- -7.6.3 to 7.7.0 - -Version 7.7.0 introduces User Groups, better user management, and security facilities. This means that anything to do with "User Types" no longer exists including APIs that work with User Types. If your code or any package's code refers to "User Type" APIs, you need to make changes to your code. In many cases, we've added backward compatibility for these scenarios and obsoleted APIs that should no longer be used. - -We are now by default using the e-mail address and not the username for the credentials. When trying to login to the backoffice you need to use the e-mail address as opposed to the username. If you do an upgrade from an older version and would like to keep using the username, change the `true` setting to **false**. - -For a full list of breaking changes see: [the list on the issue tracker](https://issues.umbraco.org/issues/?q=\&project=U4\&tagValue=\&release=7.7.0\&issueType=\&search=search) - -Version 7.7.2 no longer ships with the `CookComputing.XmlRpcV2` assembly. If you reference this assembly or have a package that requires this assembly, you need to copy it back into your website. - -This version also ships with far fewer client files that were only relevant for older versions of Umbraco (i.e. < 7.0.0). There might be some packages that were referencing these old client files. If you see missing image references you may need to contact the vendor of the package in question to update their references. - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.6.0 to 7.6.3 - -In short: - -In Umbraco version 7.6.2 we made a mistake in the Property Value Converts (PVCs). This was corrected 2 days later in version 7.6.3. If you were having problems with querying the following Data Types on the frontend, make sure to upgrade to 7.6.3: - -* Multi Node Tree Picker -* Related Links -* Member Picker - -Depending on whether you tried to fix the problem with those, you will need to fix them after you upgrade to 7.6.3. - -**Property Value Converters (PVC)** - -Umbraco stores data for Data Types in different ways. For a lot of pickers it will store `1072` or `1083,1283`. These numbers refer to the identifier of the item in Umbraco. In the past, when building your templates, you would manually have to take that value and find the content item it belongs to. Then you would be able to get the data you wanted from there. An example of that is shown below: - -```csharp -@{ - IPublishedContent contactPage; - var contactPageId = Model.Content.GetPropertyValue("contactPagePicker"); - if (contactPageId > 0) - { - contactPage = Umbraco.TypedContent(contactPageId); - } -} - -

- @contactPage.Name -

-``` - -In Umbraco 7.6.0, this is what you would do instead: - -```html -

- @Model.ContactPagePicker.Name -

-``` - -This is possible using Models Builder and through the inclusion of [core property value converters](https://our.umbraco.com/projects/developer-tools/umbraco-core-property-value-converters/), a package by community member Jeavon Leopold. - -To not break everybody's sites (the results of queries are different when PVCs are enabled), we disabled these PVCs by default. - -Umbraco 7.6.0 also came with new pickers that store their data as a [UDI (Umbraco Identifier)](https://our.umbraco.com/Documentation/Reference/Querying/Udi). We wanted to simplify the use of these new pickers and by default we wanted PVC's to always be enabled for those pickers. - -We noticed that some new pickers also got their PVC's disabled when the configuration setting was set to false (`false`). - -To make everything consistent, we made sure that the UDI pickers would always use PVC's in 7.6.2, this however reversed the behavior. So when PVC's were enabled, the property would not be converted and when PVC's were disabled, the property would be converted after all. This is the exact opposite behavior of 7.6.2. - -So we have fixed this now in 7.6.3. - -This issue only affects: - -* Multi Node Tree Picker -* Related Links -* Member Picker - -Have you already upgraded to 7.6.2 and fixed queries for those three Data Types you have to fix them again in version 7.6.3. - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.4.0 to 7.6.0 - -Find a list of all the breaking changes below and [a list of the items is also available on the tracker](http://issues.umbraco.org/issues/U4?q=Due+in+version%3A+7.6.0+Backwards+compatible%3F%3A+No+) - -The three most important things to note are: - -1. In web.config do not change `useLegacyEncoding` to `false` if it is currently set to `true` - changing the password encoding will cause you not being able to log in any more. -2. In umbracoSettings.config leave `EnablePropertyValueConverters` set to `false` - this will help your existing content queries to still work. -3. In tinyMceConfig.config make sure to remove `umbracolink` so that the rich text editor works as it should. - -**Breaking Changes** - -**Dependencies** - -**UrlRewriting.Net (**[**U4-9004**](https://issues.umbraco.org/issue/U4-9004)**)** - -`UrlRewriting` was old, leaking memory, and slowing down website startup when dealing with more than a few rules. It's entirely replaced by the [IIS Url Rewrite](https://www.iis.net/downloads/microsoft/url-rewrite) extension. - -**Json.Net (**[**U4-9499**](https://issues.umbraco.org/issue/U4-9499)**)** - -Json.Net has been updated to version 10.0.0 to benefit from improvements in features, fixes, and performances (see [release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)). This might be a breaking change for people relying on one of the changed functionality. - -**Log4net (**[**U4-1324**](https://issues.umbraco.org/issue/U4-1324)**)** - -Umbraco has used a custom build of an old (1.2.11) version of log4net that supported Medium Trust. However, Umbraco itself does not support Medium Trust anymore, and therefore log4net has been upgraded to the standard, latest build of log4net 2.0.8. - -**ImageProcessor (**[**U4-8963**](https://issues.umbraco.org/issue/U4-8963)**)** - -An optional parameter has been added to the `GetCropUrl` method in order to support the background color parameter. This breaks the method signature and therefore might require a recompile of user's code. - -**HtmlAgilityPack (**[**U4-9655**](https://issues.umbraco.org/issue/U4-9655)**)** - -The HtmlAgilityPack has been upgraded to version 1.4.9.5. The Umbraco upgrade process should take care of setting up the binding redirects appropriately. - -**Core** - -**Membership Provider Encoding (**[**U4-6566**](https://issues.umbraco.org/issue/U4-6566)**)** - -The Membership Provider `useLegacyEncoding` setting is now `false` by default, as the legacy password encoding has weaknesses. - -This change only impacts new installs (no change for upgrades). - -**Property Value Converters (**[**U4-7318**](https://issues.umbraco.org/issue/U4-7318)**)** - -A large amount of property value converters contributed by the community have been merged in and are now the default value converters. These converters change the object types returned by `GetPropertyValue` for more convenient types. - -For example, the `SliderValueConverter` returns a `decimal` or a `Range` value that can directly be used in views, instead of the comma-separated string values that were previously returned. - -This change only impacts new installs (no change for upgrades). - -The new property value converters are controlled by an `umbracoSettings.config` setting. In the section `settings/content`, setting `EnablePropertyValueConverters` needs to be present and `true` to activate them. - -**Database (**[**U4-9201**](https://issues.umbraco.org/issue/U4-9201)**)** - -Umbraco has been using a PetaPoco-managed `UmbracoDatabase` instance since version 7 came out. We realized that some of our legacy code still bypassed that mechanism and used parallel, out-of-band database connections, causing issues with transactions. - -The legacy code has been refactored to rely on the `UmbracoDatabase` instance. However, because that database is disposed of during `EndRequest`, the code that ran after it has been disposed may not work anymore. This should then be updated to use either an `HttpModule` event that occurs before `EndRequest` or the new `UmbracoModule.EndRequest` event. - -More details are available on [issue 146](https://github.com/kipusoep/UrlTracker/issues/146) on the 301 Redirect Tracker GitHub issue tracker. - -**Scopes (**[**U4-9406**](https://issues.umbraco.org/issue/U4-9406)**)** - -Version 7.6 introduces the notion of _scopes_, which allow for wrapping multiple service-level operations in one single transaction. The scopes API is partially public. Scopes are not meant for public use at this stage and we need a few more releases to ensure that the APIs are stable. - -Scopes _should not_ change how Umbraco functions. - -Introducing scopes means that some public APIs signatures are changing. Most of these changes target internal and/or non-breaking APIs (as per our [guidelines](https://our.umbraco.com/Documentation/Development-Guidelines/breaking-changes)). This should therefore have no impact on sites but may break unit tests. - -**Property Editors storing UDI instead of ID (**[**U4-9310**](https://issues.umbraco.org/issue/U4-9310)**)** - -The property editors for pickers for content, media, members, and related links have been updated to store UDI instead of the node ID. Pickers in sites being upgraded have been marked as obsolete but will continue to work as they always did. - -New sites will have the obsolete pickers filtered out from the list of available property editors, but they can be enabled by a configuration flag. - -**Rich Text Editor (RTE) Images attributes (**[**U4-6228**](https://issues.umbraco.org/issue/U4-6228)**,** [**U4-6595**](http://issues.umbraco.org/issue/U4-6595)**)** - -For a long time, we had a `rel` attribute on an `` tag when inserted into the RTE. This is invalid HTML markup. We worked around this by stripping this attribute using a Property Editor Value converter. Some developers relied on this attribute so we didn't change it to a "data-id" attribute which would have been valid. In 7.6 we are not storing integer IDs in these attributes. Instead of storing UDI values so with this change we no longer use `rel` or `data-id` and instead there will be a "data-udi" attribute. This change should affect only a small amount of people that were previously relying on the values from the "rel" attribute. - -**Others** - -We are shipping with SignalR in the core at version 2.2.1. If you already have SignalR installed into your app and are using an older version there may be conflicts. - -The creation and editing of WebForms templates will no longer be supported as for version 7.6.0. - -**Upgrading via NuGet** - -This is an important one and there was no perfect solution to this. We have removed the UrlRewriting dependency and no longer ship with it. However, if you are using it we didn't want to have NuGet delete all of your rewrites. The good news is that if you are using it, the NuGet upgrade will not delete your rewrite file and everything should continue to work. - -However, if you are not using it, **you will get an error after upgrading. Here's how to fix it:** - -Since you aren't using UrlRewriting you will have probably never edited the UrlRewriting file. In this case, NuGet will detect that and remove it. However you will need to manually remove these UrlRewriting references from your `web.config`: - -```xml -
-``` - -and - -```xml - -``` - -Remove the following `httpModules` from your `web.config`: - -```xml - - - - ... - - -``` - -and - -```xml - - - - - ... - - -``` - -**Forms** - -Umbraco Forms 6.0.0 has been released to be compatible with Umbraco 7.6. It is a new major version release of Forms primarily due to the strict dependency on 7.6+. If you are using Forms, you will need to update it to version 6.0.0 - -There are [**important Forms upgrade documentation that you will need to read.**](https://docs.umbraco.com/umbraco-forms/installation/version-specific.md#version-4-to-version-6). - -**Courier** - -Umbraco Courier 3.1.0 has been released to be compatible with Umbraco 7.6. If you are using Courier, you will need to update it to version 3.1.0. - -**Follow the** [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) **to complete the upgrade** - -
- -
- -7.3.0 to 7.4.0 - -For manual upgrades: - -* Copy the new folder `~/App_Plugins/ModelsBuilder` into the site -* Do not forget to merge `~/Config/trees.config` and `~/Config/Dashboard.config` - they contain new and updated entries that are required to be there - * If you forget `trees.config` you will either not be able to browse the Developer section or you will be logged out immediately when trying to go to the developer section -* You may experience an error saying `Invalid object name 'umbracoUser'` - this can be fixed by [clearing your cookies on localhost](http://issues.umbraco.org/issue/U4-8031) - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.2.0 to 7.3.0 - -Make sure to manually clear your cookies after updating all the files, otherwise you might an error relating to `Umbraco.Core.Security.UmbracoBackOfficeIdentity.AddUserDataClaims()`. The error looks like: `Value cannot be null. Parameter name: value`. - -NuGet will do the following for you. If you're upgrading manually make sure to also: - -* Delete `bin/Microsoft.Web.Helpers.dll` -* Delete `bin/Microsoft.Web.Mvc.FixedDisplayModes.dll` -* Delete `bin/System.Net.Http.dll` -* Delete `bin/System.Net.Http.*.dll` (all dll files starting with `System.Net.Http`) **except** for `System.Net.Http.Formatting.dll` -* Delete `bin/umbraco.XmlSerializers.dll` -* Add this in the `appSetting` section of your `web.config` file: `` - -Other considerations: - -* WebApi has been updated, normally you don’t have to do anything unless you have custom webapi configuration: - * See this article if you are using `WebApiConfig.Register`: [https://www.asp.net/mvc/overview/releases/how-to-upgrade-an-aspnet-mvc-4-and-web-api-project-to-aspnet-mvc-5-and-web-api-2](https://www.asp.net/mvc/overview/releases/how-to-upgrade-an-aspnet-mvc-4-and-web-api-project-to-aspnet-mvc-5-and-web-api-2) - * You need to update your `web.config` file to have the correct WebApi version references - this should be done by doing a compare/merge of your `~/web.config` file with the `~/web.config` file in the release -* MVC has been updated to MVC5 - * You need to update your `web.config` file to have the correct MVC version references - this should be done by doing a compare/merge of your `~/web.config` file with the `~/web.config` file in the release - * The upgrader will take care of updating all other web.config’s (in all other folders, for example, the `Views` and `App_Plugins` folders) to have the correct settings - * For general ASP.NET MVC 5 upgrade details see: [https://www.asp.net/mvc/overview/releases/how-to-upgrade-an-aspnet-mvc-4-and-web-api-project-to-aspnet-mvc-5-and-web-api-2](https://www.asp.net/mvc/overview/releases/how-to-upgrade-an-aspnet-mvc-4-and-web-api-project-to-aspnet-mvc-5-and-web-api-2) -* It is not required that you merge the changes for the Examine index paths in the ExamineIndex.config file. However, if you do, your indexes will be rebuilt on startup because Examine will detect that they don’t exist at the new location. -* It's highly recommended to clear the browser cache - the ClientDependency version is automatically bumped during installation which should force the browser cache to refresh, however in some edge cases this might not be enough. - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.1.0 to 7.2.0 - -* Copy in the `/Views/Partials/Grid` (contains Grid rendering views). - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.0.2 to 7.1.0 - -* Remove the `/Install` folder. - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.0.1 to 7.0.2 - -* There was an update to the `/umbraco/config/create/ui.xml` which needs to be manually updated. The original element had this text: - -```xml - -
User
- /create/simple.ascx - - - - -
-``` - -* The `usercontrol` value has changed to: `/create/user.ascx`. This is a required change otherwise creating a new user will not work. -* There is a breaking change to be aware of, full details can be found [here](https://umbraco.com/blog/heads-up-breaking-change-coming-in-702-and-62/). - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -7.0.0 to 7.0.1 - -* Remove all uGoLive dlls from `/bin` - * These are not compatible with V7 -* Move `appSettings/connectionStrings` back to `web.config` - * If you are on 7.0.0 you should migrate these settings into the web.config instead of having them in separate files in `/config/` - * The keys in `config/AppSettings.config` need to be moved back to the web.config `` section and similarly, the `config/ConnectionStrings.config` holds the Umbraco database connections in v7.0.0 and they should be moved back to the web.config `` section. - * `/config/AppSettings.config` and `/config/ConnectionString.config` can be removed after the contents have been moved back to `web.config`. -* Delete all files in `~/App_Data/TEMP/Razor/` - * Related to issues with razor macros - -Follow the [**upgrade guide for Umbraco 7**](minor-upgrades-for-umbraco-7.md) to complete the upgrade. - -
- -
- -6.latest to 7 - -Read and follow [the full v7 upgrade guide](upgrade-to-v7.md) - -
- -
- -4.latest to 6 - -* If your site was ever a version between 4.10.0 and 4.11.4 and you have upgraded to 6.0.0 install the [fixup package](https://our.umbraco.com/projects/developer-tools/path-fixup) and run it after the upgrade process is finished. -* The DocType Mixins package is **not** compatible with v6+ and will cause problems in your Document Types. - -
- -
- -Version 4 - -**Version 4.10.x to 4.11.x** - -* If your site was ever a version between 4.10.0 and 4.11.4 install the [fixup package](https://our.umbraco.com/projects/developer-tools/path-fixup) and run it after the upgrade process is finished. - -**Version 4.8.0 to 4.10.0** - -* Delete the `bin/umbraco.linq.core.dll` file -* Copy the new files and folders from the zip file into your site's folder - * `/App_Plugins` - * `/Views` - * `Global.asax` -* Remove the `Config/formHandlers.config` file - -**Version 4.7.2 to 4.8.0** - -* Delete the `bin/App_Browsers.dll` file -* Delete the `bin/App_global.asax.dll` file -* Delete the `bin/Fizzler.Systems.HtmlAgilityPack.dll` file -* For people using uComponents 3.1.2 or below, 4.8.0 breaks support for it. Either upgrade to a newer version beforehand or follow the workaround [posted here](https://our.umbraco.com/projects/backoffice-extensions/ucomponents/questionssuggestions/33021-Upgrading-to-Umbraco-48-breaks-support-for-uComponents) - -**Version 4.7.1.1 to 4.7.2** - -* Delete the `bin/umbraco.MacroEngines.Legacy.dll` file - -**Version 4.6.1 to 4.7.1.1** - -* Delete `bin/Iron*.dll` (all dll files starting with "Iron") -* Delete `bin/RazorEngine*.dll` (all dll files starting with "RazorEngine") -* Delete `bin/umbraco.MacroEngines.Legacy.dll` -* Delete `bin/Microsoft.Scripting.Debugging.dll` -* Delete `bin/Microsoft.Dynamic.dll` - -
diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1 (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1 (1).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1 (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1 (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1 (2).png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1 (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1.png deleted file mode 100644 index 1d8efa9c29d..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/content-on-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site (1).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site (2).png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site.png deleted file mode 100644 index 7914e6644d3..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/fresh-8_1-site.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-overwrite-dialog.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-overwrite-dialog.png deleted file mode 100644 index 9b8dd02ba54..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-overwrite-dialog.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite (1) (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite (1) (1).png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite (1).png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite.png deleted file mode 100644 index dbf7db39535..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/nuget-upgrade-overwrite.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version (1).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version (2).png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version.png deleted file mode 100644 index c0dae2344e2..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/set-umbraco-version.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1 (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1 (1).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1 (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1 (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1 (2).png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1 (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1.png deleted file mode 100644 index 8104fa85371..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrade-to-8_1.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14 (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14 (1).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14 (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14 (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14 (2).png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14 (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14.png deleted file mode 100644 index af0b40c8db7..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/upgrading-7_14.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content (1).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content (1).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content (1).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content (2).png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content (2).png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content (2).png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content.png b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content.png deleted file mode 100644 index 350e15dc720..00000000000 Binary files a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/images/v7-content.png and /dev/null differ diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/migrate-content-to-umbraco-8.md b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/migrate-content-to-umbraco-8.md deleted file mode 100644 index 69e8bdcae5e..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/migrate-content-to-umbraco-8.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -description: >- - This guide will show you how to migrate the content from your Umbraco 7 site - to a site running Umbraco 8. ---- - -# Migrate content to Umbraco 8 - -Umbraco 8 contains a lot of breaking changes and a lot of code has been cleaned up compared to Umbraco 7. Due to this, it will not be possible to do a direct upgrade from Umbraco 7 to Umbraco 8. You need to **migrate your content** from your Umbraco 7 site into your Umbraco 8 site and then recreate the rest in the new version. - -A content migration tool has been implemented in Umbraco 8.1.0, to help you with the transition. - -In this guide you can read more about the tool, its limitations, and how to use it in practice. - -{% hint style="info" %} -**Migrating Umbraco Cloud sites** - -Follow the [steps outlined in the Umbraco Cloud documentation](../../../../../umbraco-cloud/upgrades/migrate-from-umbraco-7-to-8.md) to upgrade your Umbraco 7 site on Cloud. -{% endhint %} - -## What are the limitations? - -In the following section, you can learn more about the limitations of migrating content from Umbraco 7 to Umbraco 8. - -### Versions supported - -The content migration tool is a database migration, which is made for the database schema of Umbraco 7.14+. This means that in order to do the migration you need to ensure your Umbraco 7 site is running at least Umbraco 7.14. - -### Database types supported - -Umbraco 8 does not support MySQL databases. This means that the migration will not work when moving from an Umbraco 7 site using MySQL to Umbraco 8 on SQL Server - -The database types that are supported are SQL Server and SQL CE. - -### Known issues - -Feedback from user testing has shown that some databases are harder to migrate than others. - -We are collecting [a list of these known issues on our GitHub Issue Tracker](https://github.com/umbraco/Umbraco-CMS/issues?utf8=%E2%9C%93\&q=label%3Acategory%2Fcontent-migration+). There is a community package: [Pre-migration health checks](https://our.umbraco.com/packages/developer-tools/pre-migration-health-checks/) that you can install on your Umbraco 7 site before migration. This will help identify and resolve some of these common issues before triggering the migration steps detailed below. - -{% hint style="info" %} -A migration was introduced in Umbraco 8.6 which can break the migration process. See [Issue #7914](https://github.com/umbraco/Umbraco-CMS/issues/7914) for more details. - -There are two ways to work around this issue: - -* Migrate to version 8.5 as a first step and then post-migration, carry out a normal Umbraco upgrade to the latest version of Umbraco 8, or -* Install the following community Nuget Package: [ProWorks Umbraco 8 Migrations](https://www.nuget.org/packages/ProWorks.Umbraco8.Migrations) into your Umbraco 8 project before running the migration (no configuration required). This package was created by Umbraco Gold Partner [ProWorks](https://www.proworks.com/) and patches the migration process so you can migrate directly from the latest Umbraco 7 to Umbraco 8.6+ without encountering the above issue. [Learn more about the package and the migration process on Prowork's blog](https://www.proworks.com/blog/archive/how-to-upgrade-umbraco-version-7-to-version-8). -{% endhint %} - -### Third party property editors - -The migration will transform the data stored in third party editors as well. However, it will be stored as it was in Umbraco 7. If the structure has changed or the property editor doesn't exist, you will still be able to find the data in the database. It will, however, not be available in the backoffice. - -
- -Learn more about that in the Data Types Migrations - -**Migrating data types** - -When migrating content from Umbraco 7 to Umbraco 8, the Data Type 'pre-value' structure has changed. In Umbraco 8, the term 'pre-values' no longer exists and is instead referred to as `property editor configuration`. - -In Umbraco 8, property editor configuration is a strongly typed object. There are plenty of examples in the [Umbraco-CMS codebase](https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/src/Umbraco.Web/PropertyEditors/ContentPickerConfiguration.cs). - -This configuration is stored differently in Umbraco 8 than it was in Umbraco 7. In Umbraco 7, each pre-value property was stored as a different row in a different database table. In Umbraco 8 this is simplified and property editor configuration is stored as the JSON serialized version of the strongly typed configuration object. - -When upgrading from Umbraco 7 to Umbraco 8, Umbraco has no way of knowing how custom property editors have intended to structure their configuration data. During the upgrade, Umbraco will convert the key/value pairs from the old pre-value database table into a serialized JSON version of those values. There is a reasonable chance that the end result of this data conversion is not compatible with the custom property editor. - -There are 3 options that a developer can choose to do to work around this automatic data conversion: - -**1: Implement a custom `IPreValueMigrator`** - -This option requires you to create a custom C# migrator for each of your custom property editors that store custom configuration data. It will also require that you implement these migrators before you run the Umbraco 8 content migration. - -To do this, you will create an implementation of `IPreValueMigrator` or inherit from the base class [`DefaultPreValueMigrator`](https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DefaultPreValueMigrator.cs). - -There are plenty of examples of this in the [Umbraco-CMS codebase](https://github.com/umbraco/Umbraco-CMS/tree/v8/dev/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes). - -You will then need to register them in a composer: - -```csharp -[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades -public class PreValueMigratorComposer : IUserComposer -{ - public void Compose(Composition composition) - { - composition.WithCollectionBuilder() - // Append all of the migrators required - .Append() - .Append(); - } -} -``` - -When running the migrations and encountering a custom configuration, Umbraco will utilize the `PreValueMigrator` when converting the old pre-values into the new JSON format. - -**2: Update your Angular configuration (pre-value) and property editor** - -This option means that you will choose to use the automatically converted JSON data format. In this case, it will mean updating your pre-value and property editors to use the new JSON configuration data. The converted data won't be much different than the original/intended data format so this might not be too much work. - -**3: Update the Angular configuration (pre-value) editor** - -With this option the configuration/pre-value editor needs to be updated to transform the JSON converted data into the data structure you want. When this is done and when the Data Type is saved again, the JSON data structure will be saved back to the database. Your property editor will then continue to work. - -This will require you to update and save all custom pre-value editors to transform the converted structures back to your intended data structure. - -
- -## What will happen - -When the migrations are running, Umbraco will go through your entire Umbraco 7 database and update it to the format required for Umbraco 8. The schema will be remodeled and transformed into the correct format and your existing compatible data will be transformed to fit with Umbraco 8. - -These migrations will be running directly on your database. They are transforming schema and data - not transferring. Therefore always ensure that you have a backup before attempting to do this. In case something goes wrong, you will be able to rollback and try again. - -It is highly recommended to clean up your site before running this as it will be quicker. - -* Empty Content recycle bin -* Empty Media recycle bin -* Clean up the database version history (can be done with a script or a package like [Unversion](https://our.umbraco.com/packages/website-utilities/unversion/)) - -## How it works - -In the following guide we will migrate the content of an Umbraco 7.13.1 site to Umbraco 8.1.0. - -### Step 1: Upgrading to 7.14+ - -Before the content migration can start the site has to run Umbraco 7.14+. Make sure to **always take a backup of the database** before doing an upgrade, and then check the [version specific upgrade instructions](./). - -The site in this example is an Umbraco 7.13.1 site, and we will use Nuget to update it. - -![v7 site with content](<../images/v7-content (1) (1) (1).png>) - -Following the [general upgrade instructions](../) we will now upgrade via Nuget until we get to this point: - -![Upgrading to v7.14](<../images/upgrading-7_14 (1) (1) (1) (1).png>) - -{% hint style="warning" %} -When upgrading an old website, check if you are using obsolete properties in your Data Types. These should be changed to their updated counterparts. The migration **will fail if you are still using obsolete properties.** - -The updated properties are: - -* Content Picker -* Media Picker -* Member Picker -* Multinode TreePicker -* Folder Browser -* Related Links - -You can see if your site is using the obsolete properties from the `(Obsolete)` prefix in their name. -{% endhint %} - -Install the [Pre-migration health checks plugin](https://our.umbraco.com/packages/developer-tools/pre-migration-health-checks/), and run it health check from the Developer section of the backoffice. This is done to identify and resolve some common database schema issues before migration. - -Once it is upgraded and you have verified everything is working, move on to the next step. - -### Step 2: Migrating content to Umbraco 8 - -The first thing to do is to spin up a fresh new Umbraco 8.1+ site. Make sure everything works and that no content is there. - -![Fresh 8.1 site](<../images/fresh-8_1-site (1) (1) (1).png>) - -{% hint style="warning" %} -If you have customized the `UsersMembershipProvider` on your Umbraco 7 site you need to copy that over to the 8.1 `web.config` as well. Additionally you need to update the `type` attribute to be `type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web"`. - -This also includes the attribute `useLegacyEncoding` value. Make sure that this setting is copied into your new Umbraco 8 site, as it is needed in order to log in. -{% endhint %} - -Take a backup of your database from the **Umbraco 7.14 site**. Take the information for the backup database and add that to the connectionstring for the **Umbraco 8.1 site**. If you are running SQL CE, you will have to copy the database over to the new site as well. - -Once the connectionstring is set, the final step is to change the Umbraco version number in the `web.config` on the **Umbraco 8.1 site**. Chang it to `7.14.0`. This will indicate that there is an upgrade pending and it needs to run the migration. - -![Set Umbraco version in the web.config](<../images/set-umbraco-version (1) (1) (1).png>) - -The version will be set to 8.1.0, and you need to change it to the version you are currently migrating from. - -When you start the site it will ask you to login and then show you this screen: - -![Upgrade database to 8.1](<../images/upgrade-to-8_1 (1) (1) (1).png>) - -From here, the automatic migration will take over, and after a little bit you can log in and see your content: - -![Content is on 8.1](<../images/content-on-8_1 (1) (1) (1).png>) - -{% hint style="info" %} -Please be aware that this is a **content migration**. If you go to the frontend after following these steps, it will throw errors. - -At this point you will have the content but nothing else. -{% endhint %} - -## Step 3: Files migration - -Before moving on to this step, make sure that the Umbraco 8 project is no longer running. - -The following files/folders need to be copied into the Umbraco 8 project: - -* `~/Views` - do **not** overwrite the default Macro and Partial View Macro files, unless changes have been made to these. -* `~/Media` -* Any files/folders related to Stylesheets and JavaScripts. -* Any custom files/folders the Umbraco 7 project uses, that aren't in the `~/Config` or `~/bin`. -* `~/App_Data/UmbracoForms` - in the case Umbraco Forms was used on the Umbraco 7 site. - -**Merge the configuration files carefully** to ensure any custom settings are migrated while none of the default configurations for Umbraco 8 is overwritten. - -You'll have to revisit all templates and custom implementations to get the site up and running, as all markup is still Umbraco 7-specific. - -{% hint style="info" %} -Are you planning on continuing the migration to the latest version on Umbraco CMS? - -Then you can skip the step to revisit the template files and custom implementation. We highly recommend waiting with this step until you've reached the latest version. - -If you're stopping at Umbraco 8, you can learn more about [rendering content on the Legacy Docs site](https://our.umbraco.com/Documentation/Fundamentals/Design/Rendering-Content/). -{% endhint %} - -### Step 4: Post-migration checks - -As you are updating your template files and custom implementation, you should also verify your configuration files and settings. - -Umbraco 8 contains a few changes regarding the Sections in the Umbraco Backoffice. Because of this, you should also check your User Groups and make sure they have access to the appropriate sections. - -Learn more about the Section in the [Sections article](../../../backoffice/sections.md) diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-7.md b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-7.md deleted file mode 100644 index ebb1785454b..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-7.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -description: >- - This article provides details on how to upgrade to the next minor version when - using Umbraco 7. ---- - -# Minor upgrades for Umbraco 7 - -Sometimes there are exceptions to these guidelines, which are listed in the [**version-specific guide**](./). - -## Note - -It is necessary to run the upgrade installer on each environment of your Umbraco site. If you want to update your staging and live site then you need to repeat the steps below and make sure that you click through the install screens to complete the upgrade. - -## Contents - -In this article you will find instructions for 2 different ways of upgrading: - -* [Upgrade using NuGet](minor-upgrades-for-umbraco-7.md#upgrade-using-nuget) -* [Upgrade manually from a Zip file](minor-upgrades-for-umbraco-7.md#upgrade-manually-from-a-zip-file) - -## Upgrade using NuGet - -1. Open up the **Package Console** and type: `Update-Package UmbracoCms` -2. Choose **"No to All"** by pressing the **"L"** when prompted. - * If there are any specific configuration changes required for the version you are upgrading to then they will be noted in the [**version-specific guide**](version-specific.md). - -Alternatively, you can use the Visual Studio **NuGet Package Manager** to upgrade: - -1. Open the **NuGet Package Manager** and select the **Updates** pane to get a list of available updates. -2. Choose the package called **UmbracoCms** and select update. - -The upgrade will run through all the files and make sure you have the latest changes while leaving the files you have updated. - -### Upgrades to versions lower than 7.2.0 - -If you're not upgrading to 7.2.0 or higher then you should follow these extra instructions. If you are upgrading to 7.2.0+ then you can skip this and go to [Merge UI.xml and language](minor-upgrades-for-umbraco-7.md#merge-ui-xml-and-language). - -You will be asked to overwrite your web.config file and the files in /config, make sure to answer **No** to those questions. - -For some inexplicable reason, the installation will fail if you click "No to All" (in the GUI) or answer "L" (in the package manager console) to the question: "File 'Web.config' already exists in project 'MySite'. Do you want to overwrite it?" So make sure to only answer "**No**" (in the GUI) or "**N**" (in the package manager console). - -![File conflict dialog with a web.config file in conflict](<../images/nuget-overwrite-dialog (1) (1).png>) ![File conflict console message with multiple files in conflict](<../images/nuget-upgrade-overwrite (1) (1).png>) - -We will overwrite the `web.config` file. We'll back it up so don't worry. You can find the backup in `App_Data\NuGetBackup\20140320-165450\`. The `20140320-165450` bit is the date and time when the backup occurred, which varies. You can then merge your config files and make sure they're up to date. - -## Upgrade manually from a zip file - -Download the .zip file for the new version you are upgrading to from [https://our.umbraco.com/download](https://our.umbraco.com/download) - -Copy the following folders from inside the .zip file over the existing folders in your site: - -* `/bin` -* `/Umbraco` -* `/Umbraco_Client` - -{% hint style="info" %} -There are hosting providers (we know of one: RackSpace Cloud) that require proper casing of file and folder names. Generally, on Windows, this is not a problem. Is your hosting provider forcing proper casing? You'll then need to verify that folders and files are named in the same casing as the version you're upgrading to. -{% endhint %} - -## Merge configuration files - -You can expect some changes to the following configuration files: - -* Any file in the `/Config` folder -* The `/Global.asax` file -* The `web.config` file in the root of your site **(Important: make sure to copy back the version number, and the connection string as they were.)** -* In rare cases, the `web.config` file in the Views folder - -Use a tool like [WinMerge](http://winmerge.org/) to check changes between all of the config files. Depending on when you last did this there may have been updates to a few of them. - -There's also the possibility that files in the `/Config` folder are new or have been removed(we note this in the release notes). WinMerge (and other diff tools) is able to compare folders as well so you can spot these differences. - -Up until version 6.0.0 it was necessary to change the version number in `ClientDependency.config`. This was to clear the cached HTML/CSS/JS files in the backoffice. Change the current version number to one that's higher than that. Make sure not to skip this step as you might get strange behavior in the backoffice otherwise. - -## Merge UI.xml and language - -Some packages (like Contour and Umbraco Forms) add dialogs to the `UI.xml`. Make sure to merge those changes back in from your backup during the upgrade so that the packages continue to work. This file can be found in: `/Umbraco/Config/Create/UI.xml`. - -Packages like Contour, Umbraco Forms, and Courier also make changes to the language files located in: `/Umbraco/Config/Lang/*.xml` (typically `en.xml`). - -## Finalize - -After copying the files and making the config changes, you can open your site. You should see the installer which will guide you through the upgrade. - -The installer will do two things: - -* Update the version number in the `web.config` -* Upgrade your database in case there are any changes - -We are aware that, currently, the installer is asking you for the database details of a **blank database** while upgrading. In the near future this will be pre-filled with your existing details and the wording will be updated. So no need to be scared. Enter the details of your existing database and Umbraco will upgrade it to the latest version when necessary. - -## Post installation - -One important recommendation is to always remove the `install` folder immediately after upgrading Umbraco and never to upload it to a live server. - -## Potential issues and gotchas - -### Browser cache - -Google Chrome has notoriously aggressive caching. If something doesn't seem to work well in the backoffice, make sure to clear cache and cookies thoroughly (for other browsers as well). Normally the browser cache problem is automatically handled in an Umbraco upgrade by modifying the config/ClientDependency.config version number. If you wish to re-force this update you can increment this version number. This will ensure that any server-side cache of JavaScript and stylesheets gets cleared as well. - -One way to nudge the cache in Chrome is to open the developer tools (F12) and go to the settings (the cog icon). There will be a checkbox that says "Disable cache (while DevTools is open)". Once this checkbox is on you can refresh the page and the cache should be invalidated. To force it even more, the "reload" button next to your address bar now has extra options when you right-click it. It should have "Normal reload", "Hard reload" and "Empty cache and hard reload" now. The last option is the most thorough and you might want to try that. diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-8.md b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-8.md deleted file mode 100644 index 9626570d310..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-8.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -description: This article provides details on how to upgrade to the next minor version when using Umbraco 8. ---- - -# Minor upgrades for Umbraco 8 - -Sometimes there are exceptions to these guidelines, which are listed in the **[version-specific guide](README.md)**. - -## Note - -It is necessary to run the upgrade installer on each environment of your Umbraco site. If you want to update your staging and live site you need to repeat the steps below. Make sure you click through the install screens so that your upgrade is complete. - -## Contents - -In this article you will find instructions for 3 different ways of upgrading: - -* [Upgrade using NuGet](#upgrade-using-nuget) -* [Upgrade manually from a Zip file](#upgrade-manually-from-a-zip-file) -* [Run an unattended upgrade (v8.12+)](#run-an-unattended-upgrade) - -## Upgrade using NuGet - -1. Open up the **Package Console** and type: `Update-Package UmbracoCms` -2. Choose **"No to All"** by pressing the **"L"** when prompted. - * If there are any specific configuration changes required for the version you are upgrading to then they will be noted in the **[version-specific guide](version-specific.md)**. - -Alternatively, you can use the Visual Studio **NuGet Package Manager** to upgrade: - -1. Open the **NuGet Package Manager** and select the **Updates** pane to get a list of available updates. -2. Choose the package called **UmbracoCms** and select update. - -The upgrade will run through all the files and make sure you have the latest changes while leaving files you have updated. - -## Upgrade manually from a zip file - -Download the `.zip` file for the new version you are upgrading to from [https://our.umbraco.com/download](https://our.umbraco.com/download) - -Copy the following folders from inside the `.zip` file over the existing folders in your site: - -* `/bin` -* `/Umbraco` - -{% hint style="info" %} -There are hosting providers (we know of one: RackSpace Cloud) that require proper casing of file and folder names. Normally on Windows this is not a problem. If your hosting provider however forces proper casing, you will need to verify that the folder and file names are in the same casing as in the newest version you're upgrading to. -{% endhint %} - -### Merge configuration files - -You can expect some changes to the following configuration files: - -* Any file in the `/Config` folder -* The `/Global.asax` file -* The `web.config` file in the root of your site **(Important: make sure to copy back the version number, and the connection string as they were.)** -* In rare cases, the `web.config` file in the `/Views` folder - -Use a tool like [WinMerge](http://winmerge.org/ "WinMerge") to check changes between all of the config files. Depending on when you last did this there may have been updates to few of them. - -There's also the possibility that some files in the `/Config` folder are new or some have been removed (we do make a note of this in the release notes). WinMerge (and other diff tools) can compare folders as well so you can spot these differences. - -### Merge UI.xml and language files - -Some packages like Umbraco Forms add dialogs to the `UI.xml`. Make sure to merge those changes back in from your backup during the upgrade so that the packages continue to work. This file can be found in: `/Umbraco/Config/Create/UI.xml`. - -Packages like Umbraco Forms and Courier also make changes to the language files located in: `/Umbraco/Config/Lang/*.xml` (typically `en.xml`). - -### Finalize - -After copying the files and making the config changes, you can open your site. You should see the installer which will guide you through the upgrade. - -The installer will do two things: - -* Update the version number in the `web.config` -* Upgrade your database in case there are any changes - -We are aware that, currently, the installer is asking you for the database details of a **blank database** while upgrading. In the near future this will be pre-filled with your existing details and the wording will be updated. So no need to be scared. Enter the details of your existing database and Umbraco will upgrade it to the latest version when necessary. - -## Run an unattended upgrade - -When upgrading your Umbraco project to Umbraco v8.12+ it is possible to enable the upgrade to run unattended. This means that you will not need to run through the installation wizard when upgrading. - -Below you will find the steps you need to take in order to upgrade your project unattended. - -{% hint style="info" %} -Are you running a load balanced setup with multiple servers and environments? - -Check out the section about [Unattended upgrades in a load balanced setup](#unattended-upgrades-in-a-load-balanced-setup). -{% endhint %} - -### Enable the feature - -1. Add the `Umbraco.Core.RuntimeState.UpgradeUnattended` key to `appSettings` in your web.config file. -2. Set the value of the key to `true`. - -```xml - -``` - -### Check the `ConfigurationStatus` - -In order to trigger the actual upgrade, the correct version number needs to be set. - -It is important to use the version number of the version that you are upgrading to. If this is not set, the upgrade will not run even if the `UpgradeUnattended` key has been set to `true`. - -1. Locate the `ConfigurationStatus` key in the `appSettings` section in your web.config file. -2. Update the value to match the Umbraco version that you are upgrading to. - -```xml - -``` - -### Run the upgrade - -With the correct configuration applied, the project will be upgraded on the next boot. - -{% hint style="info" %} -While the upgrade processes are running, any requests made to the site will be "put on hold", meaning that no content will be returned before the upgrade is complete. -{% endhint %} - -#### Boot order - -The Runtime level will use `Run` instead of `Upgrade` in order to allow the website to continue to boot up directly after the migration is run, instead of initiating the otherwise required restart. - -{% hint style="info" %} -The upgrade is run after Composers but before Components. This is because the migration requires services that are registered in Composers and Components requires that Umbraco and the database is ready. -{% endhint %} - -### Unattended upgrades in a load balanced setup - -Follow the steps outlined below to use run unattended upgrades in a load balanced setup. - -1. Upgrade Umbraco via NuGet in Visual Studio. Make sure the `Umbraco.Core.ConfigurationStatus` key in `appSetting` in the `web.config` file is updated to match the **target version**. -2. Deploy to all environments, including the updated `appSetting` for `Umbraco.Core.ConfigurationStatus`. -3. Set the `Umbraco.Core.RuntimeState.UpgradeUnattended` key in `appSetting` in the `web.config` to `true` for **the Main server only**. -4. Request a page on the Main server and the upgrade will run automatically. -5. Wait for the upgrade to complete. -6. Browse the Read-Only servers and make sure they do not show the “upgrade required” screen. - -## Post installation - -One important recommendation is to always remove the `install` folder immediately after upgrading Umbraco and never to upload it to a live server. - -## Potential issues and gotchas - -### Browser cache - -Google Chrome has notoriously aggressive caching, so if something doesn't seem to work well in the backoffice, make sure to clear cache and cookies thoroughly (for other browsers as well). Normally the browser cache problem is automatically handled in an Umbraco upgrade by modifying the config/ClientDependency.config version number. If you however wish to re-force this update you can increment this version number which will ensure that any server-side cache of JavaScript and stylesheets gets cleared as well. - -One way to nudge the cache in Chrome is to open the developer tools (F12) and go to the settings (the cog icon). There will be a checkbox that says "Disable cache (while DevTools is open)". Once this checkbox is on you can refresh the page and the cache should be invalidated. To force it even more, the "reload" button next to your address bar now has extra options when you right-click it. It should have "Normal reload", "Hard reload" and "Empty cache and hard reload" now. The last option is the most thorough and you might want to try that. diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/upgrade-from-8-to-latest.md b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/upgrade-from-8-to-latest.md deleted file mode 100644 index 01b7143449f..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/upgrade-from-8-to-latest.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -description: >- - Learn how to upgrade your Umbraco 8 project to Umbraco 10. ---- - -# Upgrade from Umbraco 8 to Umbraco 10 - -{% hint style="danger" %} -It is currently not possible to upgrade directly from **Umbraco 8 to the latest version**. - -The recommended approach for upgrading from version 8 to the latest version is to use this guide to upgrade from _Umbraco 8 to Umbraco 10_. Umbraco 10 contains the [database migrations](https://github.com/umbraco/Umbraco-CMS/blob/release-10.0.0/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs#L66-L73) that must be upgraded from Umbraco 8. You can then use the [Upgrading to Major](../#upgrade-to-a-new-major) steps to upgrade from _Umbraco 10 to the latest version_. -{% endhint %} - -Since the underlying framework going from Umbraco 8 to the latest version has changed, there is no direct upgrade path. That said, it is possible to re-use the database from your Umbraco 8 project on your new project in order to maintain the content. - -It is not possible to migrate the custom code as the underlying web framework has been updated from ASP.NET to ASP.NET Core. All templates and custom code will need to be reimplemented. - -You also need to make sure that the packages you are using are available on the latest version. - -## Prerequisites - -* A Umbraco 8 project running **the latest version of Umbraco 8**. -* A clean installation of the latest version of Umbraco. -* A backup of your Umbraco 8 project database. - -{% hint style="info" %} -If you use Umbraco Forms, then on the clean installation of Umbraco, you will need to install `Umbraco.Forms` package as well. -{% endhint %} - -## Video Tutorial - -{% hint style="warning" %} -The video below shows how to complete the upgrade on an Umbraco Cloud project. Most of the process is the same, however, the video does contain some Cloud-specific elements. -{% endhint %} - -{% embed url="https://www.youtube-nocookie.com/embed/wD9SGeRQR7o" %} -A video tutorial guiding you through the steps of upgrading from version 8 to the latest version on Umbraco Cloud -{% endembed %} - -## Step 1: Content Migration - -{% hint style="warning" %} -If you use Umbraco Forms, make sure to have [`StoreUmbracoFormsInDbset`](https://docs.umbraco.com/umbraco-forms/developer/forms-in-the-database#enable-storing-forms-definitions-in-the-database)to `True` before **step 1**. -{% endhint %} - -1. Create a backup of the database from your Umbraco 8 project (after you have upgraded to the latest version of v8). For this, you can use the [database backup guide](https://docs.umbraco.com/umbraco-cloud/databases/backups#backup-with-sql-server-management-studio). -2. Import the database backup into SQL Server Management Studio. -3. Update the connection string in the new projects `appsettings.json` file so that it connects to the Umbraco 8 database: - -```json -"ConnectionStrings": { - "umbracoDbDSN": "Server=YourLocalSQLServerHere;Database=NameOfYourDatabaseHere;User Id=NameOfYourUserHere;Password=YourPasswordHere;TrustServerCertificate=True" -} -``` - -{% hint style="info" %} -You can also add the connection details if you spin up a clean installation. -{% endhint %} - -4. Run the new project and login to authorize the upgrade. -5. Select "Upgrade" when the upgrade wizard appears. -6. Once the upgrade has been completed, it's recommended to login to the backoffice to verify if your project is upgraded to new version. - -{% hint style="success" %} -This is **only content migration** and the database will be migrated. - -You need to manually update the view files and custom code implementation. For more information, see Step 3 of this guide. -{% endhint %} - -## Step 2: File Migration - -1. The following files/folders need to be copied from the Umbraco 8 project into the new project: - * `~/Views` - **Do not** overwrite the default Macro and Partial View Macro files unless changes have been made to these. - * `~/Media` - Media folder from v8 needs to be copied over into the `wwwroot - media` folder - * Any files/folders related to Stylesheets and JavaScript. -2. Migrate custom configuration from the Umbraco 8 configuration files (`.config`) into the `appsettings.json` file on the new project. - * As of Umbraco version 9, the configuration no longer lives in the `Web.Config` file and has been replaced by the `appsettings.json` file. Learn more about this in the [Configuration](../../../../reference/configuration/) article. -3. [Migrate Umbraco Forms data to the database](https://docs.umbraco.com/umbraco-forms/developer/forms-in-the-database#migrating-forms-in-files-into-a-site), if relevant. - * As of Umbraco Forms version 9, it is only possible to store Forms data in the database. If Umbraco Forms was used on the Umbraco 8 project, the files need to be migrated to the database. -4. Run the new project. - * It **will** give you an error screen on the frontend as none of the Template files have been updated. - -## Step 3: Custom Code in the latest version - -The latest version of Umbraco is different from Umbraco 8 in many ways. With all the files and data migrated, it is now time to rewrite and re-implement all custom code and templates. - -### Examples of changes - -One of the changes is how published content is rendered through Template files. Due to this, it will be necessary to update **all** the Template files (`.cshtml`) to reflect these changes. - -Read more about these changes in the [IPublishedContent](../../../../reference/querying/ipublishedcontent/) section of the Umbraco CMS documentation. - -* Template files need to inherit from `Umbraco.Cms.Web.Common.Views.UmbracoViewPage` instead of `Umbraco.Web.Mvc.UmbracoViewPage` -* Template files need to use `ContentModels = Umbraco.Cms.Web.Common.PublishedModels` instead of `ContentModels = Umbraco.Web.PublishedModels` - -{% hint style="info" %} -For more information on the correct namespaces or custom code, you can find the references in the [API Documentation](../../../../reference/api-documentation.md) article. -{% endhint %} - -Depending on the extent of the project and the amount of custom code and implementations, this step is going to require a lot of work. - -Once the new project runs without errors on a local setup it is time to deploy the website to production. - -This concludes this tutorial. Find related information and further reading in the section below. - -## Related Information - -* [Issue tracker for known issues with Content Migration](https://github.com/umbraco/UmbracoDocs/issues) -* [Configuration in modern Umbraco](../../../../reference/configuration/) -* [Configuration in legacy Umbraco](https://our.umbraco.com/documentation/Reference/Configuration-for-Umbraco-7-and-8/) diff --git a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/upgrade-to-umbraco-7.md b/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/upgrade-to-umbraco-7.md deleted file mode 100644 index 01ba69a520a..00000000000 --- a/10/umbraco-cms/fundamentals/setup/upgrading/version-specific/upgrade-to-umbraco-7.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -description: >- - This document should be used as a reference, not a step by step guide. - Upgrading will largely depend on what version of Umbraco you are currently - running, what packages you have installed and the many ---- - -# Upgrade to Umbraco 7 - -The [standard upgrade instructions](../) still apply to this process as well. - -## Backup - -It is critical that you back up your website and database before upgrading. There are database changes made during installation and you cannot revert an Umbraco 7 database to an Umbraco 6 database. - -## .Net 4.5 - -Umbraco 7 is built on .Net 4.5 and your development environment will require this version installed in order to operate. Visual Studio users may require 2012 or higher. - -## HTML 5 browser support - -Umbraco 7 requires browsers with proper HTML 5 support, these include Chrome, Firefox, IE10+ - -## Breaking changes - -Before you upgrade be sure to read the list of breaking changes. This is especially recommended if you have removed or modified code in the core or if one of these breaking changes directly affects your installation. - -[See the list of breaking changes](https://our.umbraco.com/contribute/releases/700) for more details. - -## Examine - -It is recommended to rebuild all Examine indexes after completing the upgrade. - -## Xml Cache rebuild - -You should re-generate the XML cache. This can be done by following the prompts when visiting the following URL: - -`your-domain.com/umbraco/dialogs/republish.aspx?xml=true` - -## Configuration changes - -It is recommended that you use a Diff tool to compare the configuration file changes with your own current configuration files. - -* `/web.config` updates - * Details are listed here: [https://issues.umbraco.org/issue/U4-2900](https://issues.umbraco.org/issue/U4-2900) - * You will need to compare the new Umbraco 7 `web.config` with your current `web.config`. Here is a quick reference of what needs to change: - * Remove the `section name="BaseRestExtensions"` section - * Remove the `section name="FileSystemProviders"` section - * Remove the `sectionGroup name="system.web.webPages.razor"` section - * Remove the `` element - * Remove the `BaseRestExtensions` element - * Remove the `add key="umbracoUseMediumTrust"` element - * Remove the `system.web.extensions` element - * Removes the `xhtmlConformance` element - * Remove the `system.codedom` element - * Remove the `compilation` assemblies, `/compilation` - * Remove the `system.web.webPages.razor` element - * New: `sectionGroup name="umbracoConfiguration"` section - * New: `umbracoConfiguration` element - * Ensure that the `targetFramework="4.5"` is added to the `httpRuntime` element - * Add `add key="ValidationSettings:UnobtrusiveValidationMode" value="None"` to the `appSettings` element -* `/config/clientdependency.config` changes - * remove `add name="CanvasProvider"` element -* `/views/web.config` updates -* New `macroscripts/web.config` -* `config/umbracoSettings.config` - * Umbraco is now shipped with minimal settings but the [full settings](https://our.umbraco.com/documentation/Using-Umbraco/Config-files/umbracoSettings/) are still available - * `umbracoSettings` is now a true ASP.NET configuration section [https://issues.umbraco.org/issue/U4-58](https://issues.umbraco.org/issue/U4-58) - * Remove the `EnableCanvasEditing` element - * Remove the `webservices` element -* Removed `xsltExtensions.config` - * [https://issues.umbraco.org/issue/U4-2742](https://issues.umbraco.org/issue/U4-2742) -* `/config/applications.config` and `/config/trees.config` have some icon paths and names updated. You need to merge the new changes into your existing config files. -* `/config/tinyMceConfig.config` - * The `inlinepopups` is compatible and supported in Umbraco 7. You need to remove these elements: `plugin loadOnFrontend="true"`, `inlinepopups/plugin`; - * The plugins element that is shipped with Umbraco 7 looks like this: - - ```xml - - code - paste - umbracolink - anchor - charmap - table - lists - - ``` - - * You need to merge the changes from the new `tinyMceConfig` file into yours. The `command` elements that have changed are: `JustifyCenter`, `JustifyLeft`, `JustifyRight`, `JustifyFull`, `umbracomacro`, `umbracoembed`, `mceImage`, `subscript`, `superscript`, `styleselect` - * Remove the command: `mceSpellCheck` -* `/config/dashboard.config` - * You need to merge the changes from the new `dashboard.config` into yours. Some of the original dashboard entries that were shipped with Umbraco 6 have been replaced or removed. - -## Medium Trust - -Umbraco 7+ will no longer support medium trust environments. There are now some assemblies used in the core that do not support medium trust but are used extensively. Plugin scanning now also allows for scanning Umbraco's internal types which requires full trust. - -## Events - -### Tree events - -Content, Media, Members, and Data Type trees will no longer raise the legacy tree events (based on BaseTree). It is recommended to change all tree event handlers to use the new tree events that fire for every tree in Umbraco including legacy trees. The new tree events are static events and are found in the class `Umbraco.Web.Trees.TreeControllerBase`: - -* `MenuRendering` -* `RootNodeRendering` -* `TreeNodesRendering` - -### Legacy business logic events - -The Content, Media, Member, and Data Type editors have been re-created and are solely using the new Umbraco Services data layer. This means that operations performed in the backoffice will no longer raise the legacy business logic events (for example, events based on `umbraco.cms.businesslogic.web.Document`). It is recommended to change your event handlers to subscribe to the new Services data layer events. These are static events and are found in the services. For example: `Umbraco.Core.Services.ContentService.Saved`. - -## Property Editors - -Legacy property editors (pre-Umbraco 7) will not work with Umbraco 7. During the upgrade installation process, Umbraco will generate a report showing you which legacy property editors are installed. These will all be converted to a `readonly` Label property editor. No data loss will occur but you'll need to re-assign your existing data types to use a new compatible Umbraco 7 property editor. - -Most Umbraco core property editors shipped will be mapped to their equivalent Umbraco 7 editors. The Image cropper editor has not been completed for v7.0. - -### The Related Links property editor and XSLT - -Since the Related Links property is an advanced property editor, the data format has changed from XML to JSON. This should not have any effect when retrieving the data from razor. If you are outputting Related Links data with XSLT you will need to update your XSLT snippet. Making use of the new library method `umbraco.library:JsonToXml` and taking into account that the xml structure has also slightly changed. - -### GUID -> Alias mapping - -One of the database changes made in Umbraco 7 is the change of referencing a property editor from a GUID to a string alias. In order to map a legacy property editor to a new Umbraco 7 version you can add your custom "GUID -> Alias" map during application startup. To do this you would add your map using this method: `Umbraco.Core.PropertyEditors.LegacyPropertyEditorIdToAliasConverter.CreateMap` - -## Parameter Editors - -Legacy parameter editors (pre-Umbraco 7) will not work with Umbraco 7. If Umbraco detects legacy parameter editor aliases that do not map to a Umbraco 7 parameter editor it will render a textbox in its place. You will need to update your macros to use a compatible Umbraco 7 parameter editor as those that aren't supported. - -Previously, parameter editors were registered in an Umbraco database table: `cmsMacroPropertyType` which no longer exists. Parameter editors in Umbraco 7 are plugins like property editors. During the Umbraco 7 upgrade installation process it will update the new `cmsMacroProperty.editorAlias` column with the previous parameter editor alias. During this process it will look into the `Umbraco.Core.PropertyEditors.LegacyParameterEditorAliasConverter` for a map between a legacy alias to a new Umbraco 7 alias. - -Custom legacy parameters can be mapped to new Umbraco 7 parameter editor aliases during installation. This can be done by modifying the mapping during application startup using this method: `Umbraco.Core.PropertyEditors.LegacyParameterEditorAliasConverter.CreateMap`. - -## Database changes - -All database changes will be taken care of during the upgrade installation process. - -For database change details see (including all child tasks): - -* [Issue U4-2886](https://issues.umbraco.org/issue/U4-2886) -* [Issue U4-3015](https://issues.umbraco.org/issue/U4-3015) - -## Tags - -See above for the database updates made for better tag support. - -* Tags can now be assigned to a nodes property and not only a node -* Multiple tag controls can exist on one page with different data - * The legacy API does **not** support this, the legacy API will effectively, add/update/remove tags for the first property found for the document that is assigned a tag property editor. -* There is a new ITagService that can be used to query tags - * Querying for tags in a view (front-end) can be done via the new TagQuery class which is exposed from the UmbracoHelper. For example: `@Umbraco.TagQuery.GetTagsForProperty` - -## Packages - -You should check with the package creator for all installed packages to ensure they are compatible with Umbraco 7. - -## For package developers - -We see common errors that we cannot fix for you, but we do have recommendations you can follow to fix them: - -### TypeFinder - -```none -Could not load type umbraco.BusinessLogic.Utils.TypeFinder from assembly businesslogic, Version=1.0.5031.21336, Culture=neutral, PublicKeyToken=null. -``` - -The TypeFinder has been deprecated since 4.10 and is now found under `Umbraco.Core.TypeFinder`. - -### JavaScript in menu actions - -While you need to have JavaScript inside menu actions to trigger a response, it is highly recommended that you use the recommended `UmbClientMgr` methods. You should not try to override `parent.right.document` and similar tricks to get to the right-hand frame. - -### Use the recommended Umbraco uicontrols - -If you have a webforms page, it is recommended to use the built-in ASP.NET controls to render panels, properties and so on. If you use the raw HTML or try to style it to match the backoffice, you will get out of sync. Follow the guidelines set by Umbraco's internal editors and use the ASP.NET custom controls for UI. diff --git a/10/umbraco-cms/implementation/composing.md b/10/umbraco-cms/implementation/composing.md deleted file mode 100644 index bd870458d95..00000000000 --- a/10/umbraco-cms/implementation/composing.md +++ /dev/null @@ -1,486 +0,0 @@ ---- -description: "Customising the behaviour of an Umbraco Application at start up" ---- - -# Composing - -Customising the behaviour of an Umbraco Application at 'start up'. for example adding, removing, or replacing the core functionality of Umbraco or registering custom code to subscribe to notifications. - -## Overview - -An Umbraco application is a `Composition` made of many different 'collections' and single items of specific functionality/implementation logic/components (eg. UrlProviders, ContentFinders - see below for a full list). These collections are populated when the Umbraco Application starts up. - -'Composing' is the term used to describe the process of curating which pieces of functionality should be included in a particular collection. The code that implements these choices at start up is called a `Composer`. - -A `Component` is a generic wrapper for writing custom code during composition, it has two methods: `Initialize()` and `Terminate()` and these are executed when the Umbraco Application starts up, and when it shuts down, respectively. The functionality of a `Component` is identical to having a class handling both the `UmbracoApplicationStartingNotification` and `UmbracoApplicationStoppingNotification`. - -How are the collections populated? - Either by scanning the codebase for c# classes that inherit from a particular base class or implement a particular interface (typed scanned) or by being explicitly registered via a `Composer`. - -Umbraco setup the default set of components and collections that deliver the core 'out of the box' Umbraco behaviour. These default collections can be removed, reordered, replaced, etc. by implementing `IComposer`'s and `IComponent`s to customise and extend Umbraco's behaviour. - -### Example - Creating a Composer to listen for ContentSavingNotification - -This example shows how to create a component and a notification handler for the `ContentSavingNotification`, (perhaps to check for explicit words, or some custom business logic that needs to run before the content item is saved in Umbraco). - -We create a new C# class that implements `IComposer` and use it register our notification handler. - -```csharp -using System.Linq; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Extensions; - -namespace My.Website -{ - public class SubscribeToContentServiceSavingComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } - } - - public class CustomContentSavingNotificationHandler : INotificationHandler - { - public void Handle(ContentSavingNotification notification) - { - foreach (var content in notification.SavedEntities - // Check if the content item type has a specific alias - .Where(c => c.ContentType.Alias.InvariantEquals("MyContentType"))) - { - // Do something if the content is using the MyContentType doctype - } - } - } -} -``` - -{% hint style="warning" %} -Ordering of composers is important, the last one added can override a previously added composer! Make sure, when overriding, that your composer that is doing the overriding, is 'composing', after the composer has 'composed' the element you wish to override! -{% endhint %} - -### Example - Explicitly Registering a new custom OEmbedProvider - -This example shows a custom 'Spotify' OEmbed Provider which will allow Spotify URLs to be used via the 'embed' button in the Rich Text Editors. As the collection for OEmbedProviders is not 'typed scanned', we need to explicitly register the provider in the collection of OEmbedProviders. We create a C# class which implements `IComposer` and append our new Spotify OEmbedProvider to the `EmbedProvidersCollection`: - -```csharp -using Umbraco.Cms.Core.Media.EmbedProviders; -using Umbraco.Cms.Core.Serialization; - -namespace My.Website; - -public class SpotifyEmbedProvider : OEmbedProviderBase -{ - public SpotifyEmbedProvider(IJsonSerializer jsonSerializer) - : base(jsonSerializer) - { - } - - public override string ApiEndpoint => "https://embed.spotify.com/oembed/"; - - // Playlist - // https://open.spotify.com/user/spotify/playlist/37i9dQZF1E4sNI4jZloSZr?si=cueBooBfTnqCGriSa4N_Kg - // spotify:user:spotify:playlist:37i9dQZF1E4sNI4jZloSZr - // Artist - // https://open.spotify.com/artist/0iirUbtgwt9jEkc2Grin8C?si=TLeUR2cHR-KPRJJhW6YiVg - // spotify:artist:0iirUbtgwt9jEkc2Grin8C - // Album - // https://open.spotify.com/album/0lvtdqkqIln6uDBBUT7DHL?si=XTVJIEmnS_OVv9l6ktPFiw - // spotify:album:0lvtdqkqIln6uDBBUT7DHL - // Track - // https://open.spotify.com/track/7aCk4XfXIEJM2MecU6Gmf2?si=vESDzI0xTNeA9FQ_dvf1eQ - // spotify:track:7aCk4XfXIEJM2MecU6Gmf2 - public override string[] UrlSchemeRegex => new[] - { - @".*.spotify.com/.*", - @"spotify:.*" - }; - - public override Dictionary RequestParams => new(); - - public override string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) - { - string requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); - OEmbedResponse? oembed = base.GetJsonResponse(requestUrl); - - return oembed?.GetHtml(); - } -} -``` - -```csharp -using Umbraco.Cms.Core.Composing; - -namespace My.Website; - -public class RegisterEmbedProvidersComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - // Change the EmbedProvidersCollection - // by adding our new EmbedProvider for Spotify - builder.EmbedProviders().Append(); - } -} -``` - -See a list of collections below to determine which are 'type scanned' and which require explicit registration. - -### ComponentComposer - -It's an implementation of `IComposer`, that provides a quicker way to add a custom component to the Component's collection. Creating a C# class that inherits from `ComponentComposer` will automatically add `YourComponentType` to the collection of Components. In the example above, the `SubscribeToContentServiceSavingComposer` for the `SubscribeToContentServiceSavingComponent` could have been written more conveniently as: - -```csharp -public class SubscribeToContentServiceSavingComposer : ComponentComposer -{ } -``` - -## Collections - -> "Collections of elements", for example, the ContentFinders collection. - Collections are another concept that Umbraco uses to make things simpler, on top of DI. A collection builder builds a collection, allowing users to add and remove types before anything is registered into DI. - -Below is a list of collections with their corresponding 'collection type' and how items for this collection 'out of the box' are registered. - -| Collection | Type | Registration | -| ----------------------- | -------- | -------------------------------------------------------------- | -| Actions | Lazy | Type scanned for `IAction` | -| CacheRefreshers | Lazy | Type scanned for `ICacheRefresher` | -| Components | Ordered | Explicit Registration | -| ContentApps | Ordered | Package.manifest & Explicit Registration | -| ContentFinders | Ordered | Explicit Registration | -| Dashboards | Weighted | Package.manifest & Explicit Registration | -| DataEditors | Lazy | Type scanned for `IDataEditor` | -| EditorValidators | Lazy | Type scanned for `IEditorValidator` | -| HealthChecks | Lazy | Type scanned for `HealthCheck` | -| ManifestValueValidators | Set | Explicit Registration | -| OEmbedProviders | Ordered | Explicit Registration | -| PropertyValueConverters | Ordered | Type scanned for `IPropertyValueConverter` | -| SearchableTrees | Lazy | Type scanned for `ISearchableTree` | -| Sections | Ordered | Package.manifest & Explicit Registration | -| TourFilters | Base | Empty collection | -| Trees | Base | Type scanned. Must inherit `TreeControllerBase` & use `[Tree]` | -| UrlProviders | Ordered | Explicit Registration | -| UrlSegmentProviders | Ordered | Explicit Registration | -| Validators | Lazy | Explicit Registration | - -### Types of Collections - -| Type | Method | Notes | -| -------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | -| Set | `SetCollectionBuilderBase` | The base class for collection builders that do not order their items explicitly. | -| Ordered | `OrderedCollectionBuilderBase` | The base class for collection builders that order their items explicitly. | -| Weighted | `WeightedCollectionBuilder` | The base class for collection builders that order their items by the `[Weight]` attribute. | -| Lazy | `LazyCollectionBuilderBase` | The base class for collection builders that resolve the types at the last moment, only when the collection is required. | - -### Example - Modifying Collections - -This example shows how to control which Healthchecks are available to run in the Umbraco backoffice. Create a C# class which implements IUserComposer, the Compose method gives access to the HealthChecks collection of the Umbraco Composition - first we clear all HealthChecks from the collection, then add back in the ones we want to keep: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.HealthChecks.Checks.Permissions; -using Umbraco.Cms.Core.HealthChecks.Checks.Security; - -namespace My.Website -{ - public class MyComposer: IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Remove all HealthChecks - builder.HealthChecks().Clear(); - - // Explicitly add back the ones we want to use - builder.HealthChecks().Add(); - builder.HealthChecks().Add(); - } - } -} -``` - -## Attributes - -Umbraco has some useful C# attributes to decorate your composer classes or Types used in collections, to give you further control on how and when your Composers will 'compose'. - -### ComposeBefore and ComposeAfter - -A finer-grain mechanism can then be used to refine the order of composition. Each composer can specify that it should compose before or after another composer, using the ComposeBefore and ComposeAfter attributes. For instance: - -```csharp -[ComposeBefore(typeof(ThatOtherComposer))] -public class ThisComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - } -} -``` - -`ThisComposer` will 'compose' before `ThatOtherComposer`. - -{% hint style="warning" %} -If you create a circular dependency then Umbraco will fail to boot and will report the conflicting/circular dependency. -{% endhint %} - -### Weight - -This attribute is used only for `WeightedCollectionBuilders` (see list above). It specifies an integer ordinal value for each item to be added to the weighted collection which controls their sort order. The weighting attribute is not applied to the Composers. - -```csharp -using System; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Dashboards; - -namespace Umbraco.Web.Dashboards -{ - [Weight(10)] - public class FormsDashboard : IDashboard - { - public string Alias => "formsInstall"; - public string[] Sections => new [] { Constants.Applications.Forms }; - public string View => "views/dashboard/forms/formsdashboardintro.html"; - public IAccessRule[] AccessRules => Array.Empty(); - } -} -``` - -### HideFromTypeFinder - -This is used to hide a type from being auto-scanned/added to a collection as in some cases certain items/types may need to be added to a collection manually. For example, a Search package may make it optional whether to replace the 'backoffice search' with an ISearchableTree implementation. Type scanning would make this change automatically at start up if the custom implementation was detected via type scanning. This attribute could hide the class from the scanner. - -### DisableComposer & Disable - -These attributes allow you to disable a particular implementation of a composer or class - Let's say Umbraco ships with two different ways of doing "something" (for instance, two front-end caches). Each way has its own composer, which registers all the relevant elements. Keep in mind that if both composers are detected, there will be some sort of collision. Ideally, we want to disable one of them. That can be achieved with the Disable attribute: - -```csharp -[Disable] -public class Way2Composer : IComposer -{ - //... -} -``` - -When used without arguments, these attributes apply to the composer they are marking. But, and this is where it becomes interesting, they can be used with an argument to act on another component. Therefore, should a user want to replace our "something" with theirs, they would write the following code: - -```csharp -[Disable(typeof(Way1Composer))] -public class MyComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - // ... - } -} -``` - -But maybe they want to swap our two "something" implementations? In this case, assembly-level attributes can be used: - -```csharp -[assembly:DisableComposer(typeof(Way1Composer))] -[assembly:EnableComposer(typeof(Way2Composer))] -``` - -{% hint style="info" %} -Umbraco also has `[Enable]` & `[EnableComposer]` attributes but all composers are enabled by default. -{% endhint %} - -## Runtime Levels - -The `Umbraco.Cms.Core.RuntimeLevel` enum contains the following values: - -| Level | Description | -| ------------ | ----------------------------------------------------------------------------------------------------------------------------- | -| `BootFailed` | The runtime has failed to boot and cannot run. | -| `Unknown` | The level is unknown. | -| `Boot` | The runtime is booting. | -| `Install` | The runtime has detected that Umbraco is not installed at all, ie. there is no database, and is currently installing Umbraco. | -| `Upgrade` | The runtime has detected an Umbraco install which needed to be upgraded, and is currently upgrading Umbraco. | -| `Run` | The runtime has detected an up-to-date Umbraco install and is running. | - -## Example of using Ordered Collections and adding types explicitly - -You may wish to create an Umbraco package that allows package consumers to extend and add additional functionality. In this example, we show how you can use the `OrderedCollectionBuilderBase`. - -```csharp -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Web.BackOffice.Controllers; - -namespace TestCollections.Code -{ - public interface IMyThing - { - string Name { get; } - - string DoSomething(string message); - } - - public class ExampleThing : IMyThing - { - public string Name => "Example"; - - public string DoSomething(string message) - { - return $"Hello {message}"; - } - } - - // OrderedCollection - use when order of items is important (You may want to execute them in order) - // Different types of collections. - public class MyThingsCollectionBuilder : OrderedCollectionBuilderBase - { - protected override MyThingsCollectionBuilder This => this; - } - - public class MyThingsCollection : BuilderCollectionBase - { - public MyThingsCollection(Func> items) - : base(items) - { - } - } - - public static class WebCompositionExtensions - { - public static MyThingsCollectionBuilder MyThings(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - } - - public class MyThingComposer : IUserComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Explicitly add to the collection a Type in a specific order - builder.MyThings().Append() - .Append() - .Append(); - } - } - - // An Umbraco Backoffice Web API Controller - Used in a dashboard or Property Editor perhaps? - public class SomeBackofficeApiController : UmbracoAuthorizedApiController - { - private MyThingsCollection _mythings; - - public SomeBackofficeApiController() - { - } - - public SomeBackofficeApiController(MyThingsCollection mythings) - { - _mythings = mythings; - } - - public List GetMessages(string message) - { - var items = new List(); - - foreach (var thing in _mythings) - { - items.Add(thing.DoSomething(message)); - } - - return items; - } - } -} -``` - -## Example of using Lazy Collections with Type Scanning - -You may wish to create an Umbraco package that allows package consumers to extend and add additional functionality. In this example, we show how you can use the `LazyCollectionBuilderBase` to scan assemblies that implement your interface by using the `TypeLoader` - -{% hint style="warning" %} -Add types from assemblies - be conscious of doing type scanning, as this adds time to boot up of Umbraco. If you still need to use type scanning, ensure your Interface implements `IDiscoverable` as this is a type that is scanned once by Umbraco and the results are cached and then filtered. This saves time by re-scanning for types over and over again. -{% endhint %} - -```csharp -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Web.BackOffice.Controllers; - -namespace TestCollections.Code -{ - // Implement `IDiscoverable` (To help with typescanning speed/perf) - public interface IMyThing : IDiscoverable - { - string Name { get; } - string DoSomething(string message); - } - - public class ExampleThing : IMyThing - { - public string Name => "Example"; - - public string DoSomething(string message) - { - return $"Hello {message}"; - } - } - - public class MyThingsCollectionBuilder : LazyCollectionBuilderBase - { - protected override MyThingsCollectionBuilder This => this; - } - - public class MyThingsCollection : BuilderCollectionBase - { - public MyThingsCollection(Func> items) - : base(items) - { - } - } - - public static class WebCompositionExtensions - { - public static MyThingsCollectionBuilder MyThings(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - } - - public class MyThingComposer : IUserComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Add types from assemblies - be conscious of doing type scanning - // as this adds time to boot up of Umbraco - // If you still need to use type scanning, ensure your Interface implements `IDiscoverable` - builder.MyThings().Add(() => builder.TypeLoader.GetTypes()); - } - } - - // An Umbraco Backoffice Web API Controller - Used in a dashboard or Property Editor perhaps? - public class SomeBackofficeApiController : UmbracoAuthorizedApiController - { - private MyThingsCollection _mythings; - - public SomeBackofficeApiController() - { - } - - public SomeBackofficeApiController(MyThingsCollection mythings) - { - _mythings = mythings; - } - - public List GetMessages(string message) - { - var items = new List(); - - foreach (var thing in _mythings) - { - items.Add(thing.DoSomething(message)); - } - - return items; - } - } -} -``` diff --git a/10/umbraco-cms/implementation/controllers.md b/10/umbraco-cms/implementation/controllers.md deleted file mode 100644 index dc8012cda77..00000000000 --- a/10/umbraco-cms/implementation/controllers.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -product: UmbracoCms -complexity: Intermediate -audience: Developers -meta.Title: Controllers in Umbraco -description: >- - An Umbraco API Controller is an ASP.NET WebApi controller that is used for - creating REST services. ---- - -# Controllers - -Umbraco contains different types of controllers to perform different tasks: - -* [Render MVC Controllers](controllers.md#render-mvc-controllers) -* [Surface Controllers](controllers.md#surface-controllers) -* [Umbraco API Controllers](controllers.md#umbraco-api-controllers) -* [Umbraco Authorized Controllers and Attributes](controllers.md#umbraco-authorized-controllers-and-attributes) - -## Render MVC Controllers - -When you make a page request to the MVC application, a controller is responsible for returning the response to that request. The controller can perform one or more actions. - -By default, all front-end requests to an Umbraco site are auto-routed via the _Index_ action of a core Controller: `Umbraco.Cms.Web.Common.Controllers.RenderController`. - -For details on using Render MVC Controllers, see the [Controller & Action Selection](default-routing/controller-selection.md) article. - -## Surface Controllers - -A SurfaceController is an MVC controller that interacts with the front-end rendering of an UmbracoPage. They can be used for rendering view components and for handling Form data submissions. SurfaceControllers are auto-routed which means you don't have to add/create your own routes for these controllers to work. - -All implementations of Surface Controllers inherit from the base class: `Umbraco.Cms.Web.Website.Controllers.SurfaceController`. - -For details on using Surface Controllers, see the [Surface Controllers](../reference/routing/surface-controllers/) article. - -## Umbraco API Controllers - -An Umbraco API Controller is an ASP.NET WebAPI controller that is used for creating REST services. These controllers are auto-routed which means that you don't have to add/create your own routes for these controllers to work. - -All implementations of Umbraco API Controllers inherit from the base class: `Umbraco.Cms.Web.Common.Controllers.UmbracoApiController`. - -For details on using Umbraco API Controllers, see the [Umbraco API Controllers](../reference/routing/umbraco-api-controllers/) article. - -## Umbraco Authorized Controllers and Attributes - -An Umbraco Authorized Controller is used when the controller requires member or user authentication (authN) and/or authorization (authZ). If either the `authN` or `authZ` fail, the controller will return a `401 - unauthorized response`. - -### Backoffice Authorization - -The Umbraco Authorized controllers and attributes for Backoffice Users are: - -* **MVC** There is no specific controller available to inherit from. We recommend inheriting from the basic `Umbraco.Cms.Web.Common.Controllers.UmbracoController` and applying the following attributes to your method: - - * `[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]`: Uses .NET authorization using the BackOfficeAccess policy. We recommend adding extra custom authorization policies for your endpoints. - * `[DisableBrowserCache]`: Tells the browser to not cache the result. - - Remember to [add a route](../reference/routing/authorized.md#defining-a-route) for your controller. - - **Example custom authorized backoffice MVC Controller** - - ```csharp - using Microsoft.AspNetCore.Authorization; - using Microsoft.AspNetCore.Mvc; - using Umbraco.Cms.Web.Common.Authorization; - using Umbraco.Cms.Web.Common.Controllers; - using Umbraco.Cms.Web.Common.Filters; - - namespace My.Custom.Controllers; - - [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] - [DisableBrowserCache] - public class ExampleController : UmbracoController - { - public ActionResult Test() - { - TempData["Test"] = "Test"; - return View(); - } - } - ``` -* **WebAPI** - - A base class implementation for authorized auto-routed Umbraco API controllers is inherited from: `Umbraco.Cms.Web.BackOffice.Controllers.UmbracoAuthorizedApiController`. This controller inherits from `Umbraco.Cms.Web.Common.Controllers.UmbracoApiController` it is auto-routed. This controller is also attributed with `Umbraco.Cms.Web.Common.Attributes.IsBackOfficeAttribute` to ensure that it is routed correctly to be authenticated for the backoffice. - - Another base class implementation for the backoffice is `Umbraco.Cms.Web.BackOffice.Controllers.UmbracoAuthorizedJsonController`. It inherits from `Umbraco.Cms.Web.BackOffice.Controllers.UmbracoAuthorizedApiController` but has some special filters applied to it to automatically handle anti-forgery tokens for use with AngularJS in the backoffice. - -For more details on Routing requirements, see the [Routing requirements for backoffice authentication](../reference/routing/authorized.md) article. - -### Members & Front-end Authorization - -Authorizing a controller for a front-end member is achieved with attributes: - -* `Umbraco.Cms.Web.Common.Filters.UmbracoMemberAuthorizeAttribute` - Ensures authorization is successful for a website user (member). -* `Umbraco.Cms.Web.Common.Filters.UmbracoMemberAuthorizeFilter` - Ensures authorization is successful for a front-end member - -You can attribute your controller or action with this attribute which will ensure that a member must be logged in to access the resource. An example: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.Filters; -using Umbraco.Cms.Web.Website.Controllers; - -namespace UmbracoProject.Controller -{ - [UmbracoMemberAuthorize] - public class AccountController : SurfaceController - { - public AccountController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult UpdateAccountInfo(AccountInfo accountInfo) - { - // TODO: Update the account info for the current member - } - } -} -``` - -The `UmbracoMemberAuthorizeAttribute()` and `UmbracoMemberAuthorizeFilter()` contain the following properties to provide control over the authorization process for which members can access the resource: - -* `AllowType` - Comma delimited list of allowed member types. -* `AllowGroup` - Comma delimited list of allowed member groups. -* `AllowMembers` - Comma delimited list of allowed members. - -For more details, see the [Using MemberAuthorizeAttribute](../reference/routing/umbraco-api-controllers/authorization.md#using-memberauthorizeattribute) section in the Umbraco API - Authorization article. - -### Routing - -For Umbraco to authenticate a request for the backoffice, the routing needs to be specific. For details on the routes and route requirements, see the [Routing requirements for backoffice authentication](../reference/routing/authorized.md). To secure your Umbraco API controllers based on a users membership, see the [Umbraco API - Authorization](../reference/routing/umbraco-api-controllers/authorization.md) article. diff --git a/10/umbraco-cms/implementation/custom-routing/README.md b/10/umbraco-cms/implementation/custom-routing/README.md deleted file mode 100644 index bf2b8d6e39e..00000000000 --- a/10/umbraco-cms/implementation/custom-routing/README.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -product: CMS -meta.Title: Custom routing in Umbraco -description: >- - There are a couple of ways of controlling the routing behavior in Umbraco: - customizing how the inbound request pipeline finds content & creating custom - MVC routes that integrate within the Umbraco pip ---- - -# Custom Routing - -_There are a couple of ways of controlling the routing behavior in Umbraco: customizing how the inbound request pipeline finds content & creating custom MVC routes that integrate within the Umbraco pipeline_. - -## Customizing the inbound pipeline - -Below lists the ways in which you can customize the inbound request pipeline, this is done by using native Umbraco plugin classes, notifications, or defining your own routes. - -### IContentFinder - -All Umbraco content is looked up based on the URL in the current request using an `IContentFinder`. IContentFinder's you can create and implement on your own which will allow you to map any URL to a Umbraco content item. - -See: [IContentFinder documentation](../../reference/routing/request-pipeline/icontentfinder.md) - -### Last Chance IContentFinder - -A `IContentLastChanceFinder` is a special implementation of an `IContentFinder` for use with handling 404's. You can implement one of these plugins to decide which Umbraco content page you would like to show when the URL hasn't matched a Umbraco content node. - -{% hint style="info" %} -When creating packages or using class libraries, the `SetContentLastChanceFinder` is a part of the `Umbraco.Cms.Web.Website` NuGet package. -{% endhint %} - -To set your own 404 finder create a `IContentLastChanceFinder` and set it as the `ContentLastChanceFinder`. A `ContentLastChanceFinder` will always return a 404 status code. Example: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Extensions; - -namespace My.Website -{ - public class UpdateContentFindersComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - //set the last chance content finder - builder.SetContentLastChanceFinder(); - } - } -} -``` - -For more detailed information see: [IContentFinder documentation](../../reference/routing/request-pipeline/icontentfinder.md#notfoundhandlers) - -## Custom MVC routes - -You can specify your own custom MVC routes to work within the Umbraco pipeline. It requires your controller to inherit from `UmbracoPageController` and either implement `IVirtualPageController` or use `.ForUmbracoPage` when registering your route, for more information and a complete example of both approaches see [Custom routing documentation](../../reference/routing/custom-routes.md#custom-routes-within-the-umbraco-pipeline) - -An example of registering a `UmbracoPageController` using `.ForUmbracoPage`: - -```csharp -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.ApplicationBuilder; -using Umbraco.Extensions; - -namespace CustomRoutes -{ - public class MyCustomRouteComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.Configure(options => - { - options.AddFilter(new UmbracoPipelineFilter(nameof(MyController)) - { - Endpoints = app => app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - "My custom controller", - "/custom/{action}", - new {Controller = "My", Action = "Index"}) - .ForUmbracoPage(FindContent); - }) - }); - }); - } - - private IPublishedContent FindContent(ActionExecutingContext actionExecutingContext) - { - var umbracoContextAccessor = actionExecutingContext.HttpContext.RequestServices - .GetRequiredService(); - var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); - - return umbracoContext.Content.GetById(1064); - } - } -} -``` - -{% hint style="info" %} -This is an approach for mapping a custom route to a custom MVC controller. For creating routes for existing content pages you can use a custom MVC controller to handle the request by naming convention: see [Custom Controllers - Route Hijacking](../../reference/routing/custom-controllers.md). -{% endhint %} - -### RoutingRequestNotification - -You can subscribe to the `RoutingRequestNotification` which is published right after the point when the `PublishedRequestBuilder` is prepared - (but before it is ready to be processed). Here you can modify anything in the request before it is processed, eg. content, template, etc: - -```csharp -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace CustomRoutes -{ - public class PublishedRequestHandler : INotificationHandler - { - public void Handle(RoutingRequestNotification notification) - { - var requestBuilder = notification.RequestBuilder; - // Do something with the IPublishedRequestBuilder here - } - } -} -``` - -For more information on how to register and use notification handlers see [Notifications documentation](../../reference/notifications/) - -### Related articles - -* [Find out how to add your own hub(s) with SignalR to the existing setup](signalR.md)) diff --git a/10/umbraco-cms/implementation/custom-routing/signalR.md b/10/umbraco-cms/implementation/custom-routing/signalR.md deleted file mode 100644 index 5e9b25ba736..00000000000 --- a/10/umbraco-cms/implementation/custom-routing/signalR.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -description: "Umbraco ships with signalR installed, find out how to add your own hub(s) to the existing setup" ---- - -# Adding a hub with SignalR and Umbraco - -Umbraco ships with signalR installed. This article shows how to add your own hub(s) to the existing setup. - -## Create a hub and its interface - -We are going to go for the most basic implementation possible, a status ping. So first create a new interface with the following code: - -```csharp -public interface ITestHubEvents -{ - // Define the events the clients can listen to - public Task Pong(); -} -``` - -And then the actual hub: - -```csharp -using Microsoft.AspNetCore.SignalR; - -public class TestHub : Hub -{ - // when a client sends us a ping - public async Task Ping() - { - // we trigger the pong event on all clients - await Clients.All.Pong(); - } -} -``` - -### Add the routing to the Umbraco Composer - -The next step in the setup is registering our custom route: - -```csharp -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Web.Common.ApplicationBuilder; -using Umbraco.Extensions; - -public class TestHubComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - // first we are going to add signalR to the serviceCollection if no hubs have been added yet - // this is just in case Umbraco ever decides to use a different technology - if (!builder.Services.Any(x => x.ServiceType == typeof(IHubContext<>))) - { - builder.Services.AddSignalR(); - } - - builder.Services.Configure(options => - { - options.AddFilter(new UmbracoPipelineFilter( - "Signalr", - endpoints: applicationBuilder => - { - applicationBuilder.UseEndpoints(e => - { - e.MapHub($"/umbraco/{nameof(TestHub)}"); - - // Register more SignalR hubs or routes here... - }); - } - )); - }); - } -} -``` - -### Add the route in appsettings.json file - -When setting up SignalR routes, add the route to `ReservedPaths` in the `appsettings.json` file like: - -```cs -"Umbraco": { - "CMS": { - "Global": { - "ReservedPaths": "~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/,~/umbraco/testhub/," - } - } -} -``` - -{% hint style="info" %} -You need to provide the default reserved paths, else you'll run into an issue as mentioned on [GitHub](https://github.com/umbraco/Umbraco-CMS/issues/12965). -{% endhint %} - -### Test the setup - -And lastly we can test the setup with some JavaScript in our view: - -```html - - - -``` - -When you insert this in a view, you should see a `signalR connection established` console message followed by `Pong`. diff --git a/10/umbraco-cms/implementation/data-persistence.md b/10/umbraco-cms/implementation/data-persistence.md deleted file mode 100644 index f796f305f62..00000000000 --- a/10/umbraco-cms/implementation/data-persistence.md +++ /dev/null @@ -1,33 +0,0 @@ -# Data Persistence (CRUD) - -_The Umbraco Services layer is used to query and manipulate Umbraco stored in the database_. - -## Dependency injection - -All services are available using their interfaces in the dependency injection container. ASP.NET Core supports dependency injection in almost every scenario. - -### Constructors in classes - -```csharp - public class MyClass - { - private readonly IContentService _contentService; - - public MyClass(IContentService contentService) - { - _contentService = contentService; - } - } -``` - -### Constructors in views - -```cshtml - @inject IContentService ContentService -``` - -## Services - -There is a service for each type of data in Umbraco. - -[See here For a full list of services available](../reference/management/services/) diff --git a/10/umbraco-cms/implementation/default-routing/README.md b/10/umbraco-cms/implementation/default-routing/README.md deleted file mode 100644 index 2d7436a77f0..00000000000 --- a/10/umbraco-cms/implementation/default-routing/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Routing - -Get an overview of how the Umbraco pipeline is structured. See what happens from user request to content delivery. - -## Request Pipeline - -### [Inbound request pipeline](inbound-pipeline.md) - -Matching a URL to a content item & determining the rendering engine (MVC or Webforms). - -### [Controller selection](controller-selection.md) - -Match an MVC Controller and Action to handle the request. - -## [Execute request](execute-request.md) - -The MVC Action and View are executed. During this execution you can query for published data to be displayed/rendered. - -### [IPublishedContent](../../reference/querying/ipublishedcontent) - -IPublishedContent is a strongly typed underlying model used in all Umbraco views. - -### [UmbracoHelper](../../reference/querying/umbracohelper.md) - -Use UmbracoHelper to query published media and content. - -### [Members](../../reference/querying/imembermanager.md) - -This section covers the IMemberManager. diff --git a/10/umbraco-cms/implementation/default-routing/controller-selection.md b/10/umbraco-cms/implementation/default-routing/controller-selection.md deleted file mode 100644 index 641b94ac581..00000000000 --- a/10/umbraco-cms/implementation/default-routing/controller-selection.md +++ /dev/null @@ -1,88 +0,0 @@ ---- - - ---- - -# Controller & Action Selection - -When you make a page request to the MVC application, a controller is responsible for returning the response to that request. The controller can perform one or more actions. The controller action can return different types of action results based on the request. - -## Default Controller Action - -By default, Umbraco will execute every request via it's built-in default controller: `Umbraco.Cms.Web.Common.Controllers.RenderController`. Umbraco site automatically routes all the front-end requests via the `Index` action of the `RenderController`. - -```csharp -using Umbraco.Cms.Web.Common.Controllers; -using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Umbraco.Cms.Core.Web; -using Microsoft.AspNetCore.Mvc; - -namespace UmbracoProject.Controller -{ - public class HomePageController : RenderController - { - - public HomePageController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - } - public override IActionResult Index() - { - return CurrentTemplate(CurrentPage); - } - - public IActionResult HomePage() - { - return CurrentTemplate(CurrentPage); - } - } -} -``` - -## Change the Default Controllers - -It is possible to implement a custom Controller to replace the default implementation to give complete control during the Umbraco request pipeline execution. You can configure Umbraco to use your implementation in a class with a composer. For example: - -{% code title="MyRenderController.cs" lineNumbers="true" %} - -```csharp -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; -using Umbraco.Cms.Web.Website.Controllers; - -namespace YourProjectNamespace; - -public class MyRenderController : RenderController -{ - public MyRenderController( - ILogger logger, - ICompositeViewEngine compositeViewEngine, - IUmbracoContextAccessor umbracoContextAccessor) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - } - - public override IActionResult Index() => Ok("MyRenderController Index method hit with CurrentPage.Name set to: " + CurrentPage?.Name); -} - -public class MyComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.Services.Configure(renderOptions - => renderOptions.DefaultControllerType = typeof(MyRenderController)); - } -} -``` - -{% endcode %} - -Ensure that the controller inherits from the base controller `Umbraco.Cms.Web.Common.Controllers.RenderController`. You can override the `Index` method to perform any customizations of your choice. - -## Custom Controller Selection - -You can create Custom controllers for different Document Types and Templates. This is termed 'Hijacking Umbraco Routes'. For details on how this process works, see the [Custom MVC Controllers (Umbraco Route Hijacking)](../../reference/routing/custom-controllers.md) article. diff --git a/10/umbraco-cms/implementation/default-routing/execute-request.md b/10/umbraco-cms/implementation/default-routing/execute-request.md deleted file mode 100644 index cd6177c237f..00000000000 --- a/10/umbraco-cms/implementation/default-routing/execute-request.md +++ /dev/null @@ -1,34 +0,0 @@ ---- - - ---- - -# Executing an Umbraco request - -_During the Umbraco request execution, an MVC Action is called which executes a Razor view to render content to the end-user_, - -## Using the Model - -Whenever a content item is rendered on the front-end, it is based on a model of type `IPublishedContent`. This model contains all of the information about the content item associated with the current request. - -If you are working in a custom MVC Controller's action, a model of type `ContentModel` will be provided in the Action's method parameters. This model contains an instance of `IPublishedContent` which you can use. - -When you are working in a View of type `UmbracoViewPage` (which is the default view type), the Model provided to that view will be `IPublishedContent`. For example, to render the current content model's name you could do: - -```csharp -@Model.Name -``` - -All Umbraco view page types inherit from `UmbracoViewPage`. A neat trick is that if you want your view Model to be `IPublishedContent` you can change your view type to `UmbracoViewPage`. After changin the type the view will still render without issue even though the controller is passing it a model of type ContentModel. - -## [IPublishedContent](../../reference/querying/ipublishedcontent/) - -IPublishedContent is a strongly typed model used for all published content, media, and members. It is used to render content in your views for your website. - -## [UmbracoHelper](../../reference/querying/umbracohelper.md) - -UmbracoHelper is the unified way to work with published content/media on your website. Whether you are using MVC or WebForms you will be able to use UmbracoHelper to query/traverse Umbraco published data. - -## [IMemberManager](../../reference/querying/imembermanager.md) - -IMemberManager is an user manager interface for accessing member data in the form of IPublishedContent. IMemberManager has a variety of methods that are useful in views, controllers, and webforms classes. diff --git a/10/umbraco-cms/implementation/default-routing/inbound-pipeline.md b/10/umbraco-cms/implementation/default-routing/inbound-pipeline.md deleted file mode 100644 index a6b149adc0f..00000000000 --- a/10/umbraco-cms/implementation/default-routing/inbound-pipeline.md +++ /dev/null @@ -1,37 +0,0 @@ ---- - - ---- - -# Umbraco's request pipeline - -Umbraco's request pipeline is the process of building up a URL, resolving the requests, and returning correct content. - -## Published Request Preparation - -The inbound process is triggered by `UmbracoRouteValueTransformer` and then handled with the Published router. The [Published Content Request Preparation](../../reference/routing/request-pipeline/published-content-request-preparation.md) process kicks in and creates a `PublishedRequestBuilder` which will be used to create a `PublishedContentRequest`. - -What it does: - -- It ensures Umbraco is ready, and the request is a document request. -- Ensures there's content in the published cache, if there isn't it routes to the `RenderNoContentController` which displays the no content page you see when running a fresh install. -- Creates a published request builder. -- Routes the request with the request builder using the `PublishedRouter.RouteRequestAsync(…)`. - - This will handle redirects, find domain, template, published content and so on. - - Build the final `IPublishedRequest`. -- Sets the routed request in the Umbraco context, so it will be available to the controller. -- Create the route values with the `UmbracoRouteValuesFactory`. - - This is what routes your request to the correct controller and action, and allows you to hijack routes. -- Set the route values to the http context. -- Handles posted form data. -- Returns the route values to netcore so it routes your request correctly. - -## Published Content Request Instance - -When finding published content the [PublishedRouter](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Routing.PublishedRouter.html) will first check if the [PublishedRequestBuilder](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Routing.PublishedRequestBuilder.html) already has content, if it doesn't the content finders will kick in. For more information, see the [Find published content](../../reference/routing/request-pipeline/published-content-request-preparation.md#find-published-content) section in the [Published Content Request Preparation](../../reference/routing/request-pipeline/published-content-request-preparation.md) article. - -This information is also used during the [Controller & Action selection](controller-selection.md) process. - -### Related Information - -- [Routing in Umbraco](../../reference/routing/request-pipeline/) diff --git a/10/umbraco-cms/implementation/integration-testing.md b/10/umbraco-cms/implementation/integration-testing.md deleted file mode 100644 index c624b2135ba..00000000000 --- a/10/umbraco-cms/implementation/integration-testing.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -meta.Title: Integration Testing Umbraco -description: A guide to getting started with integration testing in Umbraco ---- - -# Integration Testing - -These examples are for Umbraco 10. They use [NUnit](https://nunit.org/) as the testing framework. Leveraging [Umbraco.Cms.Tests.Integration](https://github.com/umbraco/Umbraco-CMS/tree/main/tests/Umbraco.Tests.Integration) providing base classes. Beware that the Nuget package has an issue fixed in v10.3.1. So it is recommended to use this version. - -## Getting started - -First you have to create a new UnitTest project based on NUnit and install the package into the project. - -```csharp -//Create project -dotnet new nunit -//Install Umbraco.Tests.Integration package -dotnet add package Umbraco.Cms.Tests.Integration -``` - -After the project is created and the package is added we have to create an `appsettings.Tests.json` file and a GlobalSetup class. - -The `appsettings.Tests.json` can be a bit tricky, as a file with the same name is provided by the package but currently isn't picked up properly. A workaround is to create the file as `appsettings.json` and then rename the file. - -The GlobalSetup is necessary to call the `GlobalSetupTeardown` class present in the package. This class makes sure that configuration is read and everything is setup as needed. Here is a sample that can be used: - -```csharp -[SetUpFixture] -public class CustomGlobalSetupTeardown -{ - private static GlobalSetupTeardown _setupTearDown; - - [OneTimeSetUp] - public void SetUp() - { - _setupTearDown = new GlobalSetupTeardown(); - _setupTearDown.SetUp(); - } - - [OneTimeTearDown] - public void TearDown() - { - _setupTearDown.TearDown(); - } -} -``` - -Important: The class shouldn't have a namespace! - -## Creating a test - -To create a test you have to create a new class in your project. This class has to be derived from `UmbracoIntegrationTest`. This gives you access to some helper methods that you can use. - -Second is the `[UmbracoTest]`-attribute that has to be set on the class. This attribute is responsible to set which type of database setup you want to use in your test class. - -The available options are: - -* None -* NewEmptyPerFixture -* NewEmptyPerTest -* NewSchemaPerFixture -* NewSchemaPerTest - -Basic sample: - -```csharp -using Umbraco.Cms.Tests.Integration; - -[TestFixture] -[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] -public class IntegrationTests : UmbracoIntegrationTest -{ - -} -``` - -## Testing a notification - -Start by making a NotificationHandler, this example will be of one canceling overwrites on content named "Root", so if you have some content named "Root" published, you cannot change it. - -```csharp -public class MyNotificationHandler : INotificationHandler -{ - public void Handle(ContentSavingNotification notification) - { - foreach (var content in notification.SavedEntities) - { - if (content.PublishName == "Root") - { - notification.CancelOperation(new EventMessage("Cancelled", "Please do not change root content", - EventMessageType.Error)); - } - } - } -} -``` - -Then we can make an integration test, we do have to register our notification in the test like you would do with a composer, we can do this by overriding the `CustomTestSetupMethod` and adding the notification. After this, we can build our ContentType and Content with their respective builders. When we are saving both the ContentType & Content, we need the services to do so, so we use the `GetRequiredService` method that can get the services we need. We can then use `Assert.Multiple()` to do multiple asserts. - -```csharp -[TestFixture] -[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] -public class Tests : UmbracoIntegrationTest -{ - protected override void CustomTestSetup(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } - [Test] - [TestCase("Root", true, OperationResultType.FailedCancelledByEvent)] - [TestCase("Home Page", false, OperationResultType.Success)] - public void Notification_Cancels_ContentType_If_AllowAsRoot(string name, bool hasErrors, OperationResultType expectedResult) - { - //Make ContentType and save - var contentType = new ContentTypeBuilder() - .WithId(0) - .WithContentVariation(ContentVariation.Nothing) - .Build(); - var contentTypeService = GetRequiredService(); - contentTypeService.Save(contentType); - //Make some content and publish it - var content = new ContentBuilder() - .WithContentType(contentType) - .WithName(name) - .Build(); - var contentService = GetRequiredService(); - contentService.SaveAndPublish(content); - //Try to save the content - var publishResult = contentService.Save(content); - //assert - var errors = publishResult.EventMessages.GetAll() - .Where(x => x.MessageType == EventMessageType.Error); - Assert.Multiple(() => - { - Assert.AreEqual(hasErrors, errors.Any()); - Assert.AreEqual(expectedResult, publishResult.Result); - }); - } -} -``` - -## Testing with a schema - -So one of the awesome things about integration tests, is that you can set up a site, download the package for it, and we can run this state for every test. This means that you do not have to go through and set up your tests with data like we do in the above example with the builder pattern. - -To start with we decorate our class with the `[UmbracoTest]` attribute and we again derive from `UmbracoIntegrationTest`. Then what you wanna do is set up your Umbraco site, go to the packages section and create your own package. Download the package and place the XML file next to your testing class. You want to have the build action of that XML file to be `EmbeddedResource` - -Now we're almost ready to start testing! The last thing we wanna do is have a Setup method to install the package on your site. - -```csharp -[SetUp] -public void MySetup() -{ - var xml = PackageMigrationResource.GetEmbeddedPackageDataManifest(this.GetType()); - var packagingService = GetRequiredService(); - packagingService.InstallCompiledPackageData(xml); -} -``` - -Now you're all set to start testing with your own site! Let's try and see how that would look! Here's an example test, where we test that content is deleted, if you delete the Document Types, as you can see, this time we do not have to use builder patterns to set up our site! - -```csharp -[Test] -public void Ensure_No_Content_After_Doctype_Is_Deleted() -{ - var contentTypeService = GetRequiredService(); - var contentTypes = contentTypeService.GetAll(); - Assert.AreEqual(true, contentTypes.Count() > 0); - foreach (var contentType in contentTypes) - { - if (contentType.ParentId == Constants.System.Root) - { - contentTypeService.Delete(contentType); - } - } - var contentService = GetRequiredService(); - var contents = contentService.GetRootContent(); - Assert.AreEqual(0, contents.Count()); - Assert.AreEqual(0, contentTypeService.GetAll().Count()); -} -``` - -## Testing from controller to database - -Sometimes we want to test from a controller action and down to the database. In this case, we use the built-in concept of a test server. All you need to do is to use the base class UmbracoTestServerTestBase. Let’s take an example: - -```csharp -[TestFixture] -public class BackOfficeAssetsControllerTests: UmbracoTestServerTestBase -{ - [Test] - public async Task EnsureSuccessStatusCode() - { - // Arrange - var url = PrepareApiControllerUrl(x => x.GetSupportedLocales()); - - // Act - var response = await Client.GetAsync(url); - - // Assert - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - } -} -``` - -In this example you have to note three things: - -* You still need the `CustomGlobalSetupTeardown` class -* The PrepareUrl to get the URL of an Action and ensure all services use the URL information when requested. -* The Client which is a normal HttpClient, but the base URL points to the test server that is set up for each test. - -Note that you can still use GetRequiredService to get the services required to seed data. - -Keep in mind that integration tests require a lot of setup before the test executes. So execution time will be many times longer compared to a unit test. diff --git a/10/umbraco-cms/implementation/learn-how-umbraco-works.md b/10/umbraco-cms/implementation/learn-how-umbraco-works.md deleted file mode 100644 index 072d3aef0a2..00000000000 --- a/10/umbraco-cms/implementation/learn-how-umbraco-works.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: Get to know the Umbraco codebase. ---- - -# Learn how Umbraco works - -Developing an application requires knowledge about the tool you are working with. This section will give you an introduction to the underlying structure of Umbraco CMS. - -
RoutingThe process from front-end user requests to content delivery.default-routingrouting-image.png
Custom routingLearn how to work with custom URLs and custom MVC routes.custom-routingc-routing-image.png
ControllersEverything you need to know about the different types of controllers.controllers.mdcontrollers-image.png
Data persistenceLearn how to create, read, update, and delete data in the Umbraco database.data-persistence.mddatap-image.png
ComposingCustomize the behavior of an Umbraco application at 'start up'.composing.mdcomposing-image.png
Services and HelpersLearn how to use the core Services and Helpers when extending Umbraco.servicesservices-image.png
- -## Test your application - -This section also includes documentation on different ways to run tests on your code and implementations. - -{% content-ref url="integration-testing.md" %} -[integration-testing.md](integration-testing.md) -{% endcontent-ref %} - -{% content-ref url="unit-testing.md" %} -[unit-testing.md](unit-testing.md) -{% endcontent-ref %} diff --git a/10/umbraco-cms/implementation/nullable-reference-types.md b/10/umbraco-cms/implementation/nullable-reference-types.md deleted file mode 100644 index 490ee2d369a..00000000000 --- a/10/umbraco-cms/implementation/nullable-reference-types.md +++ /dev/null @@ -1,19 +0,0 @@ ---- - -Meta.Title: Nullable Reference Types -description: In this article we describe what Nullable reference types is. ---- - -# Nullable Reference Types - -From Umbraco version 10, Nullable Reference Types is enabled by default in Umbraco. - -Nullable reference types is a group of features introduced in C# 8.0. These features can be used to minimize the likelihood that your code causes the runtime to throw `System.NullReferenceException`. - -Nullable reference types includes three features that help you avoid these exceptions, including the ability to explicitly mark a reference type as nullable: - -- Improved static flow analysis that determines if a variable may be null before dereferencing it. -- Attributes that annotate APIs so that the flow analysis determines null-state. -- Variable annotations that developers use to explicitly declare the intended null-state for a variable. - -To learn more about Nullable Reference Types, refer to the [Microsoft Documentation](https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references) diff --git a/10/umbraco-cms/implementation/services/README.md b/10/umbraco-cms/implementation/services/README.md deleted file mode 100644 index 19121cca090..00000000000 --- a/10/umbraco-cms/implementation/services/README.md +++ /dev/null @@ -1,608 +0,0 @@ ---- -meta.Title: Umbraco Services and Helpers -description: >- - Umbraco has a range of 'Core' Services and Helpers that act as a 'gateway' to - Umbraco data and functionality to use when extending or implementing an - Umbraco site ---- - -# Services and Helpers - -Umbraco has a range of 'Core' Services and Helpers that act as a 'gateway' to Umbraco data and functionality to use when extending or implementing an Umbraco site. - -The general rule of thumb is that management Services provide access to allow the modification of Umbraco data (and therefore aren't optimised for displaying data). Helpers on the other hand provide access to readonly data with performance of displaying data taken into consideration. - -{% hint style="warning" %} -Although there is a management Service named the `IContentService` - only use this to modify content - do not use the `IContentService` in a View/Template to pull back data to display, this will make requests to the database and be slow - here instead inject the `IPublishedContentQueryAccessor` interface and get the `IPublishedContentQuery` that operate against a cache of published content items, and are significantly quicker. -{% endhint %} - -The management Services and Helpers are all registered with Umbraco's underlying DI framework. This article aims to show examples of gaining access to utilise these resources in multiple different scenarios. There are subtle differences to be aware of depending on what part of Umbraco is being extended. - -This article will also suggest how to follow a similar pattern to encapsulate custom 'site specific' implementation logic, in similar services and helpers, registered with the underlying DI contain. This would be to avoid repetition and promote consistency and readability within an Umbraco site solution. - -## Accessing Management Services and Helpers in a Template/View - -Inside a view/template or partial view, access is also provided by the DI framework, by using the `@inject` keyword. - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@using Umbraco.Cms.Core.Services; -@using Umbraco.Cms.Web.Common; - -@* it is really 'unlikely' to need to use a management Service in a view: *@ -@inject IRelationService RelationService -@inject UmbracoHelper Umbraco - -@{ - Layout = null; - - // retrieve an item from Umbraco's published cache with id 123 - IPublishedContent publishedContentItem = Umbraco.Content(123); -} -``` - -## Accessing Core Services and Helpers in a Controller - -Inside a [custom Controller](../../reference/routing/custom-controllers.md) access is provided to Services via the `Services` property ([ServiceContext](../../reference/management/services/)) and the `UmbracoHelper` via the `Umbraco` property ([UmbracoHelper](../../reference/querying/umbracohelper.md)). - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; - -namespace Umbraco9.Controllers -{ - public class BlogPostController : RenderController - { - private readonly ILogger _logger; - private readonly IPublishedContentQuery _publishedContentQuery; - private readonly IRelationService _relationService; - - public BlogPostController( - ILogger logger, - ICompositeViewEngine compositeViewEngine, - IUmbracoContextAccessor umbracoContextAccessor, - IPublishedContentQuery publishedContentQuery, - IRelationService relationService) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - _logger = logger; - _publishedContentQuery = publishedContentQuery; - _relationService = relationService; - } - - public override IActionResult Index() - { - // write helpful messages to the Umbraco logs to aid with debugging - _logger.LogInformation("Using core logger implementation"); - // retrieve an item from Umbraco's published cache with id 123 - IPublishedContent publishedContentItem = _publishedContentQuery.Content(123); - // it is unlikely to use a management service when rendering content from a custom controller - //(when using relationService like this you would want to provide a layer of caching) - var allRelatedUmbracoItems = _relationService.GetByParentId(CurrentPage.Id); - - return base.Index(); - } - } -} -``` - -## Accessing core Services and Helpers when there is no 'UmbracoContext' eg in a Component or C# Class - -Controllers and Views can access an `IUmbracoContext` by injecting the `IUmbracoContextAccessor`, however this is not always the case 'everywhere in Umbraco', for example common extension points: Components,ContentFinders or Custom C# Classes. - -{% hint style="warning" %} -IUmbracoContext, UmbracoHelper, IPublishedContentQuery - are all based on an HttpRequest - their lifetime is controlled by an HttpRequest. So if you are not operating within an actual request, you cannot inject these parameters and if you try to ... Umbraco will report an error on startup. -{% endhint %} - -### Injecting Services into a Component - -It's possible to inject management Services that do not rely on the `UmbracoContext` into the constructor of a component. This example shows injecting the `IMediaService` in a Notification Handler to create a corresponding Media Folder for every 'landing page' that is saved in the Content Section, by subscribing to the 'Content Saved' notification. - -```csharp -using System.Linq; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Services; - -namespace Umbraco9.Components -{ - public class SubscribeToContentSavedEventComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } - } - public class SubscribeToContentSavedNotification: INotificationHandler - { - private readonly IMediaService _mediaService; - - public SubscribeToContentSavedNotification(IMediaService mediaService) - { - _mediaService = mediaService; - } - - public void Handle(ContentSavedNotification notification) - { - foreach (var contentItem in notification.SavedEntities) - { - // if this is a new landing page create a folder for associated media in the media section - if (contentItem.ContentType.Alias == "landingPage") - { - // we have injected in the mediaService in the constructor for the component see above. - bool hasExistingFolder = _mediaService.GetByLevel(1).Any(f => f.Name == contentItem.Name); - if (!hasExistingFolder) - { - // let's create one (-1 indicates the root of the media section) - IMedia newFolder = _mediaService.CreateMedia(contentItem.Name, -1, "Folder"); - _mediaService.Save(newFolder); - } - } - } - } - } -} -``` - -See documentation on [Composing](../composing.md) for further examples and information on Components and Composition. - -### Accessing Published Content outside of a Http Request - -Trying to inject types that are based on an Http Request such as `UmbracoHelper` or `IPublishedContentQuery` into classes that are not based on an Http Request will trigger an error. However, there is a technique that allows the querying of the Umbraco Published Content, using the `UmbracoContextFactory` and calling `EnsureUmbracoContext()`. - -In this example, when a page is unpublished, instead of a 404 occurring for the content when the url is requested in the future, we might want to serve a 410 'page gone' status code instead. We handle the Unpublishing notification of the ContentService, access the Published Content Cache, determine it's 'published url' and then store for later use in any 'serving the 410' mechanism. - -An [IContentFinder](../../reference/routing/request-pipeline/icontentfinder.md) could be placed in the ContentFinder ordered collection, right before a 404 is served. This could be done to lookup the incoming request against the stored location of 410 urls, and serve the 410 status request code if a match is found for the previously published item. - -```csharp -using System; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Web; -using Umbraco.Extensions; - -namespace Umbraco9.Components -{ - public class HandleUnPublishingEventComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } - } - - public class HandleUnPublishingHandler : INotificationHandler - { - private readonly IUmbracoContextFactory _umbracoContextFactory; - - public HandleUnPublishingHandler(IUmbracoContextFactory umbracoContextFactory) - { - _umbracoContextFactory = umbracoContextFactory; - } - - public void Handle(ContentUnpublishedNotification notification) - { - // for each unpublished item, we want to find the url that it was previously 'published under' and store in a database table or similar - using (UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext()) - { - // the UmbracoContextReference provides access to the ContentCache - IPublishedContentCache contentCache = umbracoContextReference.UmbracoContext.Content; - - foreach (var item in notification.UnpublishedEntities) - { - if (item.ContentType.Alias == "blogpost") - { - // item being unpublished will still be in the cache, as unpublishing event fires before the cache is updated. - IPublishedContent soonToBeUnPublishedItem = contentCache.GetById(item.Id); - - if (soonToBeUnPublishedItem != null) - { - string previouslyPublishedUrl = soonToBeUnPublishedItem.Url(); - - if (!string.IsNullOrEmpty(previouslyPublishedUrl) && previouslyPublishedUrl != "#") - { - _customFourTenService.InsertFourTenUrl(previouslyPublishedUrl, DateTime.UtcNow); - } - } - } - } - } - } - } -} -``` - -#### Accessing the Published Content Cache from a Content Finder / UrlProvider - -Inside a ContentFinder access to the content cache is possible by injecting `IUmbracoContextAccessor` into the constructor and provided via the PublishedRequest object: - -```csharp -public Task TryFindContent(IPublishedRequestBuilder request) -{ - if (!UmbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) - { - return false; - } - var someContent = umbracoContext.Content.GetById(1234); - - // ... -} -``` - -And inside an `IPublishedUrlProvider` injection of `IUmbracoContextAccessor` into the constructor is also possible. - -```csharp -private readonly IUmbracoContextAccessor _umbracoContextAccessor; - -public MyCustomUrlProvider(IUmbracoContextAccessor umbracoContextAccessor) -{ - _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); -} - -public override UrlInfo GetUrl(IPublishedContent content, UrlMode mode = UrlMode.Default, string culture = null, Uri current = null) -{ - - var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); - var someContent = umbracoContext.Content.GetById(1234); - - // ... -} -``` - -{% hint style="info" %} -It is still possible to inject services into IContentFinder's. IContentFinders are singletons, but the example is showing you do not 'need to' in order to access the Published Content Cache. -{% endhint %} - -## Customizing Services and Helpers - -When implementing an Umbraco site, it is likely to have to execute similar code that accesses or operates on Umbraco data, in multiple places, perhaps using the core management Services or Umbraco Helpers. - -For example; Getting a list of the latest News Articles, or building a link to the site's News Section or Contact Us page. Repeating this kind of logic in multiple places, Views, Partial Views / Controllers etc, is possible, but it's generally considered good practice to consolidate this logic into a single place. - -### Extension methods - -One option is to add 'Extension Methods' to the `UmbracoHelper` class or `IPublishedContentQuery` interface. - -```csharp -using System.Linq; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Extensions; - -namespace Umbraco9.Components -{ - public static class PublishedContentQueryExtensions - { - public static IPublishedContent GetNewsSection(this IPublishedContentQuery publishedContentQuery) - { - // assuming a single site with a single News Section at the top level - IPublishedContent siteRoot = publishedContentQuery.ContentAtRoot().FirstOrDefault(); - // make sure siteRoot isn't null, then locate first child content item with alias 'newsSection' - return siteRoot?.FirstChild(f => f.ContentType.Alias == "newsSection") ?? null; - } - } -} -``` - -Anywhere there is reference to the `UmbracoHelper` or `IPublishedContentQuery` and a reference is added to the namespace the extension belongs to, it is possible to call the method by writing `_publishedContentQuery.GetNewsSection()`. - -### Custom Services and Helpers - -Another option, is to make use of the underlying DI framework, and create custom Services and Helpers, that in turn can have the 'core' management Services and Umbraco Helpers injected into them. - -This approach enables the grouping together of similar methods within a suitably named service, and promotes the possibility of testing this custom logic outside of Controllers and Views. - -{% hint style="warning" %} -Depending on where the custom service will be utilised, we will dictate the best practice approach to accessing the 'Published Content Cache'. If it is 100% guaranteed that the service will only be called from a place with an UmbracoContext, eg a controller or view, then it is safe to inject `IPublishedContentQuery` etc for simplicity. However if the custom service is called in a location without UmbracoContext (eg an notification handler) it will fail. Therefore the approach of accessing the Published Content Cache via injecting IUmbracoContextFactory and calling `EnsureUmbracoContext()` will provide consistency across any custom services no matter where they are utilised. -{% endhint %} - -In this example, we create a custom service, that's responsible for finding key pages within a site, eg the News Section or the Contact Us page. These methods will commonly be called in different places throughout the site, and it's great to encapsulate the logic to retrieve them in a single place - we'll call this service `SiteService`. - -Create an interface to define the service: - -```csharp -using Umbraco.Cms.Core.Models.PublishedContent; - -namespace Umbraco9.Services -{ - public interface ISiteService - { - IPublishedContent GetNewsSection(); - IPublishedContent GetContactUsPage(); - } -} -``` - -Create the concrete service class that implements the interface: - -```csharp -using System; -using Umbraco.Cms.Core.Models.PublishedContent; - -namespace Umbraco9.Services -{ - public class SiteService : ISiteService - { - public IPublishedContent GetNewsSection() - { - // TODO: implement this! - throw new NotImplementedException(); - } - - public IPublishedContent GetContactUsPage() - { - // TODO: implement this! - throw new NotImplementedException(); - } - } -} -``` - -Register the custom service with Umbraco's underlying DI container using an `IComposer`: - -```csharp -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco9.Services -{ - public class RegisterSiteServiceComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddSingleton(); - } - } -} -``` - -#### Lifetimes - -**"Transient"** services can be injected into "Transient" and below ⤵. (i.e. "Transient" services can be injected anywhere) - -* "Transient" means that anytime this type is needed a brand new instance of this type will be created. - -**"Scope"** services can be injected into "Request"/"Scope" based lifetimes only - -* "Scope" means that a single instance of this type will be created for the duration of the current HttpRequest. The instance will be disposed of at the end of the current HttpRequest. - -**"Singleton"** services can be injected into "Singletons" and below ⤵. - -* "Singleton" means that only a single instance of this type will ever be created for the lifetime of the application. - -#### Implementing the service - -**1 - The service will ONLY be used during a request like in a Controller or View** - -You can avoid repeating common implementation logic in multiple controllers and views. This is done by consolidating these implementations into a custom service. If you are very familiar with IPublishedContentQuery injecting this into the custom service is straight forward, but the caveat is you can only use this service in a controller/view. - -For example, locating the 'special' pages in the site using the familiar syntax of the `IPublishedContentQuery`: - -```csharp -using System.Linq; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Extensions; - -namespace Umbraco9.Services -{ - public class SiteService : ISiteService - { - private readonly IPublishedContentQuery _contentQuery; - public SiteService(IPublishedContentQuery contentQuery) - { - _contentQuery = contentQuery; - } - public IPublishedContent GetNewsSection() - { - var siteRoot = _contentQuery.ContentAtRoot().FirstOrDefault(); - var newsSection = siteRoot?.FirstChild(f => f.ContentType.Alias == "newsSection") ?? null; - return newsSection; - } - public IPublishedContent GetContactUsPage() - { - var siteRoot = _contentQuery.ContentAtRoot().FirstOrDefault(); - var contactUs = siteRoot?.FirstChild(f => f.ContentType.Alias == "contactUs") ?? null; - return contactUs; - } - } -} -``` - -**2 - The service can be used within or outside of a web request** - -```csharp -using System.Linq; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Web; -using Umbraco.Extensions; - -namespace Umbraco9.Services -{ - public class SiteService : ISiteService - { - private readonly IUmbracoContextFactory _umbracoContextFactory; - - public SiteService(IUmbracoContextFactory umbracoContextFactory) - { - _umbracoContextFactory = umbracoContextFactory; - } - public IPublishedContent GetNewsSection() - { - using var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); - var contentQuery = umbracoContextReference.UmbracoContext.Content; - var siteRoot = contentQuery.GetAtRoot().FirstOrDefault(); - var newsSection = siteRoot?.FirstChild(f => f.ContentType.Alias == "newsSection") ?? null; - return newsSection; - } - public IPublishedContent GetContactUsPage() - { - using var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); - var contentQuery = umbracoContextReference.UmbracoContext.Content; - var siteRoot = contentQuery.GetAtRoot().FirstOrDefault(); - var contactUs = siteRoot?.FirstChild(f => f.ContentType.Alias == "contactUs") ?? null; - return contactUs; - } - } -} -``` - -The second approach can seem 'different' or more complex at first glance, but it is the syntax and method names that are slightly different... it enables the registering of the service in Singleton Scope, and its use outside of controllers and views. - -{% hint style="info" %} -Occasionally, you may face a situation where Umbraco fails to boot, due to a circular dependency on `IUmbracoContextFactory`. This can happen if your service interacts with third party code that also depends on an `IUmbracoContextFactory` instance (e.g. an Umbraco package). - -See the [Circular Dependencies](circular-dependencies.md) article for an example on how to get around this. -{% endhint %} - -**Aside: What is the IUmbracoContextAccessor then?** - -The `IUmbracoContextFactory` will obtain an `UmbracoContext` by first checking to see if one exists on the current thread using the `IUmbracoContextAccessor`. This is a singleton that can be injected anywhere and whose function is to provide access to the current UmbracoContext. On a 'non request' thread the IUmbracoContextAccessor's TryGetUmbracoContext method will return false and the IUmbracoContextFactory will create a new instance of the UmbracoContext. - -If you need to know whether the UmbracoContext has been obtained from an existing thread, or whether it has been freshly created, you can 'inject' `IUmbracoContextAccessor` yourself. This will check if the UmbracoContext is null using the TryGetUmbracoContext method, indicating whether you are in a 'non request' thread or not. You will still need to inject and use an IUmbracoContextFactory if you subsequently want to obtain an UmbracoContext in a non-request thread. - -```csharp -using System.Linq; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; -using Umbraco.Web.PublishedCache; - -namespace Umbraco9.Services -{ - public class SiteService : ISiteService - { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IUmbracoContextFactory _umbracoContextFactory; - - public SiteService(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoContextFactory umbracoContextFactory) - { - _umbracoContextAccessor = umbracoContextAccessor; - _umbracoContextFactory = umbracoContextFactory; - bool hasUmbracoContext = _umbracoContextAccessor.TryGetUmbracoContext(out _); - } -``` - -NB: With the `IUmbracoContextAccessor` and `IUmbracoContextFactory` you should NEVER have to inject the UmbracoContext itself directly into any of your constructors. - -#### Using the custom SiteService inside a Controller - -Because we've registered the SiteService with Umbraco's underlying DI framework we can inject the service into our controller's constructor, in the same way as 'core' Services and Helpers. - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; -using Umbraco9.Services; - -namespace Umbraco9.Controllers -{ - public class BlogPostController : RenderController - { - private readonly ISiteService _siteService; - - public BlogPostController( - ILogger logger, - ICompositeViewEngine compositeViewEngine, - IUmbracoContextAccessor umbracoContextAccessor, - ISiteService siteService) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - _siteService = siteService; - } - public override IActionResult Index() - { - var newsSection = _siteService.GetNewsSection(); - var blogPostViewModel = new BlogPostViewModel(CurrentPage); - blogPostViewModel.HasNewsSection = false; - if (newsSection != null) - { - blogPostViewModel.HasNewsSection = true; - blogPostViewModel.NewsSection = newsSection; - } - - // etc - // Do other stuff here!, then return the custom viewmodel to the template view. - return CurrentTemplate(blogPostViewModel); - } - } -} -``` - -You can generate this in Visual Studio by using either ctrl + . or alt + enter when your cursor is on the base class: - -
- -#### Using the SiteService inside a View - -If strictly following the paradigm of MVC, calling custom Services from Views might feel like an anti-pattern. However there isn't necessarily one single 'best practice' approach to working with Umbraco. A lot depends on circumstance, expertise and pragmatism. Allowing Umbraco to handle the flow of incoming requests to a particular page + template, and writing implementation logic in Views/Templates, is still a very common approach. There are circumstances, where the custom implementation logic shared is very 'View' specific. Custom logic for constructing 'Alternative Text' for images or different crop urls for img srcsets can be neatly handled in a custom Helper/Service without having to create a hijacked MVC route for the request and build a complex ViewModel. Custom Services called from Views, can help separate the concerns, even if the 'plumbing' isn't pure MVC. - -To access the service directly from the view you would need to use the Razor `@inject` keyword to get a reference to the concrete implementation of the service registered with DI: - -```csharp -@using Umbraco9.Services - -@inject ISiteService SiteService -@inherits UmbracoViewPage -@{ - - IPublishedContent newsSection = SiteService.GetNewsSection(); -} -
-
-
-``` - -### Handle routes as server-side requests - -Sometimes you might want to request, for example "/sitemap.xml" from your server, but since this has a file extension it will be treated as a client-side request and will not work. You can configure routes to be handled as server-side requests in your startup.cs. - -**For a single route:** - -```csharp -services.Configure(options => -{ - options.HandleAsServerSideRequest = httpRequest => - { - return httpRequest.Path.StartsWithSegments("/sitemap.xml"); - }; -}); -``` - -**For multiple routes:** - -```csharp -services.Configure(options => -{ - string[] allowList = new[] {"/sitemap.xml", "robots.txt", ...}; - options.HandleAsServerSideRequest = httpRequest => - { - foreach (string route in allowList) - { - if (httpRequest.Path.StartsWithSegments(route)) - { - return true; - } - } - - return false; - }; -}); -``` diff --git a/10/umbraco-cms/implementation/services/circular-dependencies.md b/10/umbraco-cms/implementation/services/circular-dependencies.md deleted file mode 100644 index b441409309d..00000000000 --- a/10/umbraco-cms/implementation/services/circular-dependencies.md +++ /dev/null @@ -1,30 +0,0 @@ ---- - - ---- - -# Circular Dependencies - -In some cases you might experience that a circular dependency is preventing your Umbraco installing from starting up. - -An example of this could be a circular dependency on `IUmbracoContextFactory`. This would happen if your service interacts with third-party code that also depends on an `IUmbracoContextFactory` instance. - -In this situation, you can request a lazy version of the dependency so it won't evaluate during boot, only when accessed: - -```csharp -public class SiteService : ISiteService -{ - private readonly Lazy _umbracoContextFactory; - public SiteService(Lazy umbracoContextFactory) - { - _umbracoContextFactory = umbracoContextFactory; - } - public IPublishedContent GetNewsSection() - { - using (UmbracoContextReference umbracoContextReference = _umbracoContextFactory.Value.EnsureUmbracoContext()) - { - // Do your thing - } - } -} -``` diff --git a/10/umbraco-cms/implementation/services/images/vs-di-constructor-generation-tip.gif b/10/umbraco-cms/implementation/services/images/vs-di-constructor-generation-tip.gif deleted file mode 100644 index edf5db7a78c..00000000000 Binary files a/10/umbraco-cms/implementation/services/images/vs-di-constructor-generation-tip.gif and /dev/null differ diff --git a/10/umbraco-cms/implementation/unit-testing.md b/10/umbraco-cms/implementation/unit-testing.md deleted file mode 100644 index 397d8852c95..00000000000 --- a/10/umbraco-cms/implementation/unit-testing.md +++ /dev/null @@ -1,265 +0,0 @@ ---- -meta.Title: Unit Testing Umbraco -description: A guide to getting started with unit testing in Umbraco ---- - -# Unit Testing Umbraco - -These examples inspire unit testing in Umbraco with Umbraco 9.x, 10.x, 11.x and 12.x, using [NUnit](https://nunit.org/), [Moq](https://github.com/moq/moq4), and [AutoFixture](https://github.com/AutoFixture/AutoFixture). There are many ways of testing Umbraco and there’s no right or wrong way. - -When testing components in Umbraco, such as controllers, helpers, services etc. these components often require that you provide a couple of dependencies in your classes using [dependency injection](../reference/using-ioc.md). This is because a lot of magic happens “under the hood” of Umbraco and these dependencies are needed for that magic to happen. - -{% hint style="info" %} -Writing Unit Tests increases awareness of underlying dependencies, enhancing your skills as an Umbraco developer. -{% endhint %} - -## Mocking - -These tests follows an approach thats based on isolating your tests from Umbraco and mock as much of Umbraco’s dependencies as possible. Think of it like you’re not testing Umbraco, you’re testing how your implementation code interacts with Umbraco’s behavior. - -Once you become familiar with these underlying dependencies, you may consider replacing them with actual implementations. This can lean towards integration or end-to-end testing, but the decision is yours. Again these examples should be a source of inspiration and the quickest way to get started with Unit Testing. - -{% hint style="info" %} -If you are new to mocking you can read more on this topic [here](https://martinfowler.com/bliki/TestDouble.html) or use the [Moq Quickstart](https://github.com/Moq/moq4/wiki/Quickstart) guide. For more inspiration and other ways of how to write tests in Umbraco there's a blogpost from HQ member Bjarke Berg about [Automated Testing](https://umbraco.com/blog/automated-testing-in-umbraco/). -{% endhint %} - -### Testing a ContentModel - -See [Reference documentation on Executing an Umbraco request](default-routing/execute-request.md#executing-an-umbraco-request). - -```csharp -public class PageViewModel : ContentModel -{ - public PageViewModel(IPublishedContent content) : base(content) { } - - public string Heading => (string)this.Content.GetProperty(nameof(Heading)).GetValue(); -} - -public class PageViewModelTests -{ - [Test, AutoData] - public void Given_PublishedContent_When_GetHeading_Then_ReturnPageViewModelWithHeading(string value, Mock content) - { - SetupPropertyValue(content, nameof(PageViewModel.Heading), value); - - var viewModel = new PageViewModel(content.Object); - - Assert.AreEqual(value, viewModel.Heading); - } - - public void SetupPropertyValue(Mock content, string propertyAlias, string propertyValue, string culture = null) - { - var property = new Mock(); - property.Setup(x => x.Alias).Returns(nameof(PageViewModel.Heading)); - property.Setup(x => x.GetValue(culture, null)).Returns(propertyValue); - content.Setup(x => x.GetProperty(propertyAlias)).Returns(property.Object); - } -} -``` - -### Testing a RenderController - -See [Reference documentation for Custom controllers (Hijacking Umbraco Routes)](../reference/routing/custom-controllers.md#creating-a-custom-controller). - -```csharp -public class PageController : RenderController -{ - public PageController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, compositeViewEngine, umbracoContextAccessor) { } - - public IActionResult Page(ContentModel model) - { - return View(new PageViewModel(model.Content)); - } -} - -public class PageControllerTests -{ - private PageController controller; - - [SetUp] - public void SetUp() - { - this.controller = new PageController(Mock.Of>(), Mock.Of(), Mock.Of()); - } - - [Test, AutoData] - public void When_PageAction_ThenResultIsIsAssignableFromContentResult(Mock content) - { - var model = new ContentModel(content.Object); - - var result = this.controller.Page(model); - - Assert.IsAssignableFrom(result); - } - - [Test, AutoData] - public void Given_PublishedContentHasHeading_When_PageAction_Then_ReturnViewModelWithHeading_With_AutoFixture(string value, Mock content) - { - SetupPropertyValue(content, nameof(PageViewModel.Heading), value); - - var viewModel = (PageViewModel)((ViewResult)this.controller.Page(new ContentModel(content.Object))).ViewData.Model; - - Assert.AreEqual(value, viewModel.Heading); - } - - public void SetupPropertyValue(Mock content, string propertyAlias, string propertyValue, string culture = null) - { - var property = new Mock(); - property.Setup(x => x.Alias).Returns(nameof(PageViewModel.Heading)); - property.Setup(x => x.GetValue(culture, null)).Returns(propertyValue); - content.Setup(x => x.GetProperty(propertyAlias)).Returns(property.Object); - } -} -``` - -### Testing a SurfaceController - -See [Reference documentation on SurfaceControllers](../reference/routing/surface-controllers/). - -```csharp -public class PageSurfaceController : SurfaceController -{ - public PageSurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) { } - - [HttpPost] - public IActionResult Submit() - { - return Content("H5YR!"); - } -} - -public class PageSurfaceControllerTests -{ - private PageSurfaceController controller; - - [SetUp] - public void SetUp() - { - this.controller = new PageSurfaceController(Mock.Of(), Mock.Of(), ServiceContext.CreatePartial(), AppCaches.NoCache, Mock.Of(), Mock.Of()); - } - - [Test] - public void When_SubmitAction_ThenResultIsIsAssignableFromContentResult() - { - var result = this.controller.Submit(); - - Assert.IsAssignableFrom(result); - } - - [Test] - public void When_SubmitAction_Then_ExpectHelloWorld() - { - var result = (ContentResult)this.controller.Submit(); - - Assert.AreEqual("H5YR!", result.Content); - } -} -``` - -{% hint style="info" %} -`ServiceContext.CreatePartial()` has optional parameters, and by naming them you only need to mock the dependencies that you need, for example: `ServiceContext.CreatePartial(contentService: Mock.Of());` -{% endhint %} - -## Testing an UmbracoApiController - -See [Reference documentation on UmbracoApiControllers](../reference/routing/umbraco-api-controllers/README.md#locally-declared-controller). - -```csharp -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] { "Table", "Chair", "Desk", "Computer", "Beer fridge" }; - } - - [HttpGet] - public JsonResult GetAllProductsJson() - { - return new JsonResult(this.GetAllProducts()); - } -} - -public class ProductsControllerTests -{ - private ProductsController controller; - - [SetUp] - public void SetUp() - { - this.controller = new ProductsController(); - } - - [Test] - public void WhenGetAllProducts_ThenReturnViewModelWithExpectedProducts() - { - var expected = new[] { "Table", "Chair", "Desk", "Computer", "Beer fridge" }; - - var result = this.controller.GetAllProducts(); - - Assert.AreEqual(expected, result); - } - - [Test] - public void WhenGetAllProductsJson_ThenReturnViewModelWithExpectedJson() - { - var json = JsonConvert.SerializeObject(this.controller.GetAllProductsJson().Value); - - Assert.AreEqual("[\"Table\",\"Chair\",\"Desk\",\"Computer\",\"Beer fridge\"]", json); - } -} -``` - -## Testing ICultureDictionary using the UmbracoHelper - -See [Core documentation on the interface ICultureDictionary](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Dictionary.ICultureDictionary.html). - -```csharp -public class HomeController : RenderController -{ - private readonly UmbracoHelper umbracoHelper; - - public HomeController(UmbracoHelper umbracoHelper, ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, compositeViewEngine, umbracoContextAccessor) - { - this.umbracoHelper = umbracoHelper; - } - - public IActionResult Home(ContentModel model) - { - var myCustomModel = new PageViewModel(model.Content) - { - MyDictionaryProperty = this.umbracoHelper.GetDictionaryValue("myDictionaryKey") - }; - - return View(myCustomModel); - } -} - -public class HomeControllerTests -{ - private Mock cultureDictionary; - private Mock cultureDictionaryFactory; - private UmbracoHelper umbracoHelper; - private HomeController controller; - - [SetUp] - public void SetUp() - { - this.cultureDictionary = new Mock(); - this.cultureDictionaryFactory = new Mock(); - this.cultureDictionaryFactory.Setup(x => x.CreateDictionary()).Returns(this.cultureDictionary.Object); - this.umbracoHelper = new UmbracoHelper(this.cultureDictionaryFactory.Object, Mock.Of(), Mock.Of()); - this.controller = new HomeController(this.umbracoHelper, Mock.Of>(), Mock.Of(), Mock.Of()); - } - - [Test, AutoData] - public void GivenMyDictionaryKey_WhenIndexAction_ThenReturnViewModelWithMyPropertyDictionaryValue(string expected) - { - var model = new ContentModel(new Mock().Object); - this.cultureDictionary.Setup(x => x["myDictionaryKey"]).Returns(expected); - - var result = (PageViewModel)((ViewResult)this.controller.Home(model)).Model; - - Assert.AreEqual(expected, result.MyDictionaryProperty); - } -} -``` diff --git a/10/umbraco-cms/legacy-documentation/README.md b/10/umbraco-cms/legacy-documentation/README.md deleted file mode 100644 index 01174b16a74..00000000000 --- a/10/umbraco-cms/legacy-documentation/README.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -description: Resources and links for older versions of Umbraco CMS. ---- - -# Legacy Documentation - -This documentation platform covers only major versions of the Umbraco CMS since Umbraco 9. If you are using an older version of Umbraco CMS, you will need to go elsewhere. - -The documentation for Umbraco 7 and 8 lives on [our.umbraco.com](https://our.umbraco.com/documentation/). - -
Umbraco 7 Documentationhttps://our.umbraco.com/documentation/
Umbraco 8 Documentationhttps://our.umbraco.com/documentation/
Umbraco EOL Documentationhttps://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions
diff --git a/10/umbraco-cms/reference/angular/README.md b/10/umbraco-cms/reference/angular/README.md deleted file mode 100644 index 0f16cc74ae6..00000000000 --- a/10/umbraco-cms/reference/angular/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# AngularJS - -The Umbraco backoffice is built using AngularJS. The implementation is made up of many directives and services. - -{% hint style="warning" %} -**As of Umbraco 10, this section will no longer be updated.** - -Please refer to the [Backoffice UI API Documentation](../../extending/backoffice-ui-api-documentation.md) article instead. - -For any questions regarding the above, feel free to reach out at [docs@umbraco.com](mailto:docs@umbraco.com). - -You can also raise an issue on the [official UmbracoDocs GitHub Issue Tracker](https://github.com/umbraco/UmbracoDocs/issues). -{% endhint %} - -Generally, you can find information about these via the [Backoffice UI API documentation](https://apidocs.umbraco.com/v12/ui). This part of the documentation is auto-generated from the Umbraco source code. - -Below you can find more in-depth descriptions and examples of AngularJS directives and services. - -## Directives - -* [Layout selector](directives/umblayoutselector.md) (``) -* [Load indicator](directives/umbloadindicator.md) (``) -* [Property](directives/umbproperty.md) (``) - -## Services - -* [Editor service](services/editorservice.md) -* [Events service](services/eventsservice/) diff --git a/10/umbraco-cms/reference/angular/directives/README.md b/10/umbraco-cms/reference/angular/directives/README.md deleted file mode 100644 index 228224c9f97..00000000000 --- a/10/umbraco-cms/reference/angular/directives/README.md +++ /dev/null @@ -1,10 +0,0 @@ ---- - - ---- - -# Directives - -- [Layout selector](umblayoutselector.md) (``) -- [Load indicator](umbloadindicator.md) (``) -- [Property](umbproperty.md) (``) diff --git a/10/umbraco-cms/reference/angular/directives/images/umbLayoutSelector.png b/10/umbraco-cms/reference/angular/directives/images/umbLayoutSelector.png deleted file mode 100644 index b3cc9b5f64b..00000000000 Binary files a/10/umbraco-cms/reference/angular/directives/images/umbLayoutSelector.png and /dev/null differ diff --git a/10/umbraco-cms/reference/angular/directives/images/umbLoadIndicator.gif b/10/umbraco-cms/reference/angular/directives/images/umbLoadIndicator.gif deleted file mode 100644 index 66e74e371e6..00000000000 Binary files a/10/umbraco-cms/reference/angular/directives/images/umbLoadIndicator.gif and /dev/null differ diff --git a/10/umbraco-cms/reference/angular/directives/umblayoutselector.md b/10/umbraco-cms/reference/angular/directives/umblayoutselector.md deleted file mode 100644 index 71e9b817831..00000000000 --- a/10/umbraco-cms/reference/angular/directives/umblayoutselector.md +++ /dev/null @@ -1,64 +0,0 @@ -# umbLayoutSelector - -When you have a list of items, you can use the `umb-layout-selector` directive to let users toggle between different layouts. For instance, in Umbraco's media archive, users can select between a grid-based layout (thumbnails) and a list-based layout (table). - -![Example of the layout selector](images/umbLayoutSelector.png) - -The directive has three attributes: - -* `layouts` is used to indicate the available layouts that the user should be able to select. -* `active-layout` is a reference to the layout currently being used. -* `on-layout-select` is a callback function triggered when the user chooses another layout. - -For a view utilizing this directive: - -* The HTML could look something like this: - - ```html -
- - -
- ``` -* You'd also need a controller for initializing the different values to be used for the directive: - - ```js - angular.module("umbraco").controller("myController", function ($scope) { - - // Declare the available layouts - $scope.layouts = [ - { - name: "Grid", - icon: "icon-thumbnails-small", - path: "gridpath", - selected : true - }, - { - name: "List", - icon: "icon-list", - path: "listpath", - selected: true - } - ]; - - // Declare the function called by the directive when user chooses another layout - $scope.selectLayout = function(layout) { - $scope.activeLayout = layout; - $scope.layouts.forEach(element => element.active = false); - layout.active = true; - }; - - // Select the first layout - $scope.selectLayout($scope.layouts[0]); - - }); - ``` - -For each layout: - -* `name` property indicates the visual name of the layout (eg. used when hovering over the layout in the selector) -* `icon` is the CSS selector for the icon of the layout. -* `path` attribute indicates a sort of alias, and is used internally for comparing the layouts. -* Each layout should also have a `selected` property indicating whether a particular layout is enabled, and thereby visible in the selector. diff --git a/10/umbraco-cms/reference/angular/directives/umbloadindicator.md b/10/umbraco-cms/reference/angular/directives/umbloadindicator.md deleted file mode 100644 index eaa33169756..00000000000 --- a/10/umbraco-cms/reference/angular/directives/umbloadindicator.md +++ /dev/null @@ -1,27 +0,0 @@ -# umbLoadIndicator - -Many web sites and web applications use a form of load indicator to indicate a busy state to the user. Throughout the backoffice, Umbraco uses three animated circles as a load indicator - eg. as shown below: - -![Example of the load indicator](images/umbLoadIndicator.gif) - -Umbraco internally does this via the `` directive, which you can also use in your own views for the backoffice. - -The directive doesn't have any parameters on it's own. Since you most likely only wish to show the load indicator during certain states of your code, you can control this either through `ng-if` or `ng-show`. - -For instance if your controller sets the `loading` variable to `true` during busy states: - -```html - -``` - -The directive uses CSS and absolute position to center it self in. For instance, if you're also using the `` directive, you can set it's position to `relative`: - -```html - - - - - -``` - -As seen on the animation in the beginning of this page, the load indicator is centered in the white box. diff --git a/10/umbraco-cms/reference/angular/directives/umbproperty.md b/10/umbraco-cms/reference/angular/directives/umbproperty.md deleted file mode 100644 index c591ec5f774..00000000000 --- a/10/umbraco-cms/reference/angular/directives/umbproperty.md +++ /dev/null @@ -1,33 +0,0 @@ ---- - ---- - -# umbProperty - -The [umb-property](https://apidocs.umbraco.com/v10/ui#/api/umbraco.directives.directive:umbProperty) directive can along with [umb-property-editor](https://apidocs.umbraco.com/v10/ui#/api/umbraco.directives.directive:umbPropertyEditor) be used for rendering property editors in the backoffice. - -The two directives are typically used together. For instance, if your Angular model has an array of properties, your view could look something like: - -```html - - - -``` - -`Properties` contains the model for each property. `ng-repeat` can be used to iterate over each property, passing them to the two directives via `property` and `model` attributes. - -For a basic property with a textbox, the model for the property can be defined as: - -```javascript -var property = { - alias: "myProperty", - label: "My property", - description: "This is my property.", - value: "Cupcake ipsum dolor sit amet oat cake marzipan...", - view: "textbox" -}; -``` - -The `view` property specifies the URL to the property editor that should be used for this property. To use one of the built-in property editors in Umbraco, you can specify the alias (eg. `textbox`) rather than the full URL to the view (eg. `/umbraco/Views/propertyeditors/textbox/textbox.html`). - -You can see a list of all the built-in property editors in the [propertyeditors folder on GitHub](https://github.com/umbraco/Umbraco-CMS/tree/83107bb31a7fe98f6c5b0a601c0e8ee898cd274b/src/Umbraco.Web.UI.Client/src/views/propertyeditors). diff --git a/10/umbraco-cms/reference/angular/services/README.md b/10/umbraco-cms/reference/angular/services/README.md deleted file mode 100644 index e8828abcdb6..00000000000 --- a/10/umbraco-cms/reference/angular/services/README.md +++ /dev/null @@ -1,12 +0,0 @@ ---- - - ---- - -# Services - -- [**Editor service**](editorservice.md) - Service for opening and working with editors and overlays. - -- [**Events service**](eventsservice/) - Service for listening and sending broadcasts. diff --git a/10/umbraco-cms/reference/angular/services/editorservice.md b/10/umbraco-cms/reference/angular/services/editorservice.md deleted file mode 100644 index af2e5731187..00000000000 --- a/10/umbraco-cms/reference/angular/services/editorservice.md +++ /dev/null @@ -1,83 +0,0 @@ ---- - ---- - -# Editor Service - -The Angular `editorService` service is the primary resource used for opening overlays and handling infinite editing. Besides the `open` and `close` functions, the service also contains functions for opening specialized overlays/editors - eg. `contentPicker` or `mediaPicker`. - -## Content Picker - -The `contentPicker` function opens a Content Picker in infinite editing. Depending on the options, it may be used for picking a single content item or a set of content items. Options for the function is as following: - -| Alias | Description | -|-----------------|-------------| -| **multiPicker** | Indicates a boolean value for whether the editor should work as a single Content Picker (`false`) or a Multi Content Picker (`true`). | -| **submit** | Is a callback function when the user selects and submits one or more content items. | -| **close** | Is a callback function when the close button is clicked. | - -The Content Picker could be opened as: - -```js -editorService.contentPicker({ - multiPicker: true, - submit: function(model) { - model.selection.forEach(item, function() { - console.log(item.name); - }); - editorService.close(); - }, - close: function() { - editorService.close(); - } -}); -``` - -This example snippet will open a new Multi Content Picker. If the user submits one or more content items, the name of each content item will be printed to the console. The user may also close the Content Picker without selecting any content items, in which case the `close` callback function is invoked. - -## Document Type Editor - -The `documentTypeEditor` function of the editor service can be used for opening a new overlay for creating a new Document Type. It can also be used for editing an existing Document Type. - -The function supports the following options: - -| Alias | Description | -|----------------|-------------| -| **id** | Indicates the numeric ID of the Document Type which should be opened for editing. | -| **create** | A boolean value indicating whether the overlay should be used for creating a new Document Type (opposed to editing an existing Document Type). | -| **noTemplate** | When part of a create-overlay, this option specifies whether the Document Type should be created without a corresponding Template. | -| **submit** | A callback function for when the user submits/saves the Document Type. | -| **close** | A callback function for when the close button is clicked. | - -An overlay for creating a new Document Type may be opened as: - -```javascript -editorService.documentTypeEditor({ - id: -1, - create: true, - submit: function (model) { - console.log(model.documentTypeAlias); - editorService.close(); - }, - close: function () { - editorService.close(); - } -}); -``` - -Notice that both the `id` and `create` options must be specified. When the overlay submits, you'll be able to get the alias of the created Document Type through `model.documentTypeAlias`. - -Opening an overlay for editing an existing Document Type can be opened as: - -```javascript -editorService.documentTypeEditor({ - id: 1103, - submit: function (model) { - console.log(model.documentTypeAlias); - editorService.close(); - }, - close: function () { - editorService.close(); - } -}); -``` diff --git a/10/umbraco-cms/reference/angular/services/eventsservice/README.md b/10/umbraco-cms/reference/angular/services/eventsservice/README.md deleted file mode 100644 index b2a8f7af071..00000000000 --- a/10/umbraco-cms/reference/angular/services/eventsservice/README.md +++ /dev/null @@ -1,511 +0,0 @@ ---- - -needsV9Update: "true" ---- - -# Events Service - -The events service allows different components in Umbraco to broadcast and listen for global events. - -## Using the events service in your custom code - -### Broadcasting an event - -To broadcast an event, you can use the `emit` function. It takes two arguments, where the first is the name of the event - eg. `featured.updated`, and the second argument is an object or similar describing the event. - -The second argument is optional, so if your use case doesn't need this, feel free to skip this argument. - -The illustrate this function, you could have a controller with an `updated` function that is triggered by the view. In this dummy example, the function will increment the value of a property editor, and then use the events service to broadcast that the value was updated: - -```javascript -angular.module("umbraco").controller("MyController", function($scope, eventsService) { - - $scope.updated = function() { - $scope.model.value++; - eventsService.emit("feature.updated", { value: $scope.model.value }); - }; - -}); -``` - -### Listening for an event - -Another controller could then listen for broadcasts of your `feature.updated` event via the events service's `on` function, which takes the name of the event as the first argument, and a callback function as the second argument. - -Then in the callback function, the first argument is the event it self, and the second argument is the object we pass on to the `emit` function when we're broadcasting: - -```javascript -angular.module("umbraco").controller("MyOtherController", function($scope, eventsService) { - - $scope.count = 0; - - // Subscribe to the event - var unsubscribe = eventsService.on("feature.updated", function(event, args) { - $scope.count = args.value; - }); - - // When the scope is destroyed we need to unsubscribe - $scope.$on("$destroy", function () { - unsubscribe(); - }); - -}); -``` - -#### Listening for events globally -Controllers are typically used by a specific component, so the controller will only be executed when such a component is inserted into the DOM. The controller will be executed for each component, so you may end of with multiple instances listening for the same event. - -If you need to listen for events on a more global level, you can hook into the application startup using `app.run(...)`: - -```javascript -app.run(function (eventsService) { - - $scope.count = 0; - - // Subscribe to the event - var unsubscribe = eventsService.on("feature.updated", function(event, args) { - $scope.count = args.value; - }); - -}); -``` - -### Unsubscribing from an event - -Notice how the result of the `on` function is saved in an `unsubscribe` variable. When we add a listener via the `on` function, it's important to clean up after our selves when our component (here a controller) no longer exists - eg. when removed from the DOM. - -In Angular, we can listen for the `$destroy` event in the current scope, and then unsubscribe from the events service by calling the `unsubscribe` variable as a function. - -Alternatively, we could replace `unsubscribe()` with `eventsService.unsubscribe(unsubscribe)`, but it does the same thing - so calling the variable as a function directly may be preferred as it's shorter. - - - - - - - -## Events in Umbraco - -Below you'll find a list of events broadcasted by the Umbraco codebase. The list may not be complete, so please help updating the list should you find an event that isn't listed. - -### Umbraco application - -#### Init - -**When the Umbraco application is ready** - -```javascript -eventsService.emit("app.ready", data); -``` - - - -#### Security interceptor - -When Umbraco our your custom code makes a request to the server via the `$http` service, Umbraco listens for the `x-umb-user-modified` header in the response. In can be used to tell the Umbraco backoffice that the current user has been modified, in which case Umbraco knows that it should refetch the user data. - -```javascript -if (headers["x-umb-user-modified"]) { - eventsService.emit("app.userRefresh"); -} -``` - - - - -### Services - -#### Clipboard service - -**When the clipboard in local storage is updated** - -```js -eventsService.emit("clipboardService.storageUpdate"); -``` - - - -#### Editor service - -**When an editor is opened** - -```javascript -var args = { - editors: editors, - editor: editor -}; - -eventsService.emit("appState.editors.open", args); -``` - - - -**When an editor is closed** - -```javascript -var args = { - editors: editors, - editor: closedEditor -}; - -// emit event to let components know an editor has been removed -eventsService.emit("appState.editors.close", args); -``` - - - -**When all editors are closed** - -```javascript -var args = { - editors: editors, - editor: null -}; - -eventsService.emit("appState.editors.close", args); -``` - - - -#### Editor State service - -```javascript -eventsService.emit("editorState.changed", { entity: entity }); -``` - - - -#### Localization service - -**When the language resource file is loaded from the server** - -````javascript -eventsService.emit("localizationService.updated", response.data); -```` - - - -#### Overlay service - -**When an overlay is opened** - -```javascript -eventsService.emit("appState.overlay", overlay); -``` - - - -**When an overlay is closed** - -```javascript -eventsService.emit("appState.overlay", null); -``` - - - -#### TinyMCE service - -**When upload of a file starts** - -```javascript -eventsService.emit("rte.file.uploading"); -``` - - - -**When upload of a file ends** - -```js -eventsService.emit("rte.file.uploaded"); -``` - - - -**When the user presses CTRL + S** - -```js -eventsService.emit("rte.shortcut.save"); -``` - - - -#### Tours - -**When tours are loaded** - -```javascript -eventsService.emit("appState.tour.updatedTours", tours); -``` - - - -**When user starts a tour** - -```javascript -eventsService.emit("appState.tour.start", tour); -``` - - - -**When user ends a tour** - -```javascript -eventsService.emit("appState.tour.end", tour); -``` - - - -**When a tour is disabled** - -```javascript -eventsService.emit("appState.tour.end", tour); -``` - - - -**When user completes a tour** - -```javascript -eventsService.emit("appState.tour.complete", tour); -``` - - - -#### Tree service - -**When loading a tree node fails** - -```javascript -eventsService.emit("treeService.treeNodeLoadError", { error: reason }); -``` - - - -**When a tree node is removed** - -```javascript -eventsService.emit("treeService.removeNode", { node: treeNode }); -``` - - - -#### User service - -**When the user is logged out** - -```javascript -const args = { isTimedOut: isTimedOut }; -eventsService.emit("app.notAuthenticated", args); -``` - - - -**When user is trying to log in, but have not start nodes** - -```javascript -var result = { errorMsg: errorMsg, user: data, authenticated: false, lastUserId: lastUserId, loginType: "credentials" }; -eventsService.emit("app.notAuthenticated", result); -``` - -**When user is successfully authenticated** - -```javascript -var result = { user: data, authenticated: true, lastUserId: lastUserId, loginType: "credentials" }; -eventsService.emit("app.authenticated", result); -``` - - - -**When user data is refetched from the server** - -```javascript -if (args && args.broadcastEvent) { - //broadcast a global event, will inform listening controllers to load in the user specific data - eventsService.emit("app.authenticated", result); -} -``` - - - -#### Util service - -**When the app is initialized** - -```javascript -eventsService.emit("app.reInitialize"); -``` - - - - - - - - - - -### Directives - -#### Toggle directive - -**When the toggle is initialized** - -```javascript -eventsService.emit("toggleValue", { value: scope.checked }); -``` - - - -**When the toggle is clicked** - -```javascript -eventsService.emit("toggleValue", { value: !scope.checked }); -``` - - - - - - - - - - - - - - - - - - - - - - - - - -### Controllers - -#### Grid controller - -**When a new row is added** - -```javascript -eventsService.emit("grid.rowAdded", { scope: $scope, element: $element, row: row }); -``` - - - -**When a new control is added** - -```javascript -eventsService.emit("grid.itemAdded", { scope: $scope, element: $element, cell: cell, item: newControl }); -``` - - - -**When the grid is initializing** - -```javascript -eventsService.emit("grid.initializing", { scope: $scope, element: $element }); -``` - - - -**When the grid is initialized** - -```javascript -eventsService.emit("grid.initialized", { scope: $scope, element: $element }); -``` - - - -#### Languages overview controller - -**When a language is deleted** - -```c# -eventsService.emit("editors.languages.languageDeleted", args); -``` - - - - - - -### Other - -**Setting the page title** - -Available from 8.4.0 - -``` -$scope.$emit("$changeTitle", title); -``` - -For more information see [Change title](changetitle.md) diff --git a/10/umbraco-cms/reference/angular/services/eventsservice/changetitle.md b/10/umbraco-cms/reference/angular/services/eventsservice/changetitle.md deleted file mode 100644 index 0a0ad2d15f8..00000000000 --- a/10/umbraco-cms/reference/angular/services/eventsservice/changetitle.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -versionFrom: 8.4.0 -needsV9Update: 'true' ---- - -# changeTitle - -Setting the title of the page the user is working on is important for accessibility purposes. People using assistive technology need to know what they are maintaining. By setting the page title, people who work with multiple tabs will also find the page they were working on. - -To use the directive call: - -``` -$scope.$emit("$changeTitle", title); -``` - -When the user navigates through the site there is some logic which sets the default page title this is based on: - -* The current section the user is in -* The deployment environment - -![Example of the default title](images/defaultview.png) - -The original title of the page is based on the section being edited and the host name. - -![Example of the page title showing edit blo](images/editblog.png) - -The title to use will then be prefixed to the original title of the page. - -To remove the title displayed and revert to the default title, pass in an empty string. diff --git a/10/umbraco-cms/reference/angular/services/eventsservice/images/defaultview.png b/10/umbraco-cms/reference/angular/services/eventsservice/images/defaultview.png deleted file mode 100644 index 7931e5f2f51..00000000000 Binary files a/10/umbraco-cms/reference/angular/services/eventsservice/images/defaultview.png and /dev/null differ diff --git a/10/umbraco-cms/reference/angular/services/eventsservice/images/editblog.png b/10/umbraco-cms/reference/angular/services/eventsservice/images/editblog.png deleted file mode 100644 index e3efa802397..00000000000 Binary files a/10/umbraco-cms/reference/angular/services/eventsservice/images/editblog.png and /dev/null differ diff --git a/10/umbraco-cms/reference/api-documentation.md b/10/umbraco-cms/reference/api-documentation.md deleted file mode 100644 index accd1e6a843..00000000000 --- a/10/umbraco-cms/reference/api-documentation.md +++ /dev/null @@ -1,39 +0,0 @@ ---- - -meta.Title: "Umbraco API Documentation" -description: "Information on Umbraco API Documentation" ---- - -# API Documentation - -A library of API Reference documentation is auto-generated from the comments within the Umbraco Source Code. - -## C# API Documentation - -C# API references for the Umbraco Core, Infrastructure, Extensions and Web libraries. - -### [Umbraco.Core](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.html) - -### [Umbraco.Infrastructure](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Infrastructure.html) - -### [Umbraco.Web](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Web.Common.html) - -### [Umbraco.Extensions](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Extensions.html) - -{% hint style="info" %} -opens a documentation browser that is different from the documentation section you're viewing now. -{% endhint %} - -## Backoffice UI API Documentation - -Angular, JavaScript, CSS & Less UI API references for building Umbraco backoffice components. - -- The umbraco.directives -- The umbraco.services -- The umbraco.resources - -### [Backoffice UI](https://apidocs.umbraco.com/v10/ui) - -{% hint style="info" %} -opens a documentation browser that is different from the documentation section you're viewing now. -{% endhint %} diff --git a/10/umbraco-cms/reference/cache/README.md b/10/umbraco-cms/reference/cache/README.md deleted file mode 100644 index 054dffbb3df..00000000000 --- a/10/umbraco-cms/reference/cache/README.md +++ /dev/null @@ -1,93 +0,0 @@ ---- - - ---- - -# Cache & Distributed Cache - -_This section refers to how to implement caching features in the Umbraco application in a consistent way that will work in both single server environments and load balanced (multi-server) environments. The caching described in this section relates to application caching in the context of a web application only._ - -{% hint style="warning" %} **Please read this if you are Caching** - -Although caching is a pretty standard concept it is very important to make sure that caching is done correctly and consistently. It is always best to ensure performance is at its best before applying any cache and also beware of _over caching_ as this can cause degraded performance in your application because of cache turnover. - -In normal environments caching seems to be a pretty standard concept. If you are a package developer or developer who is going to publish a codebase to a load balanced environment then you need to be aware of how to invalidate your cache properly, so that it works in load balanced environments. If it is not done correctly then your package and/or codebase will not work the way that you would expect in a load balanced scenario. - -**If you're caching business logic based on backoffice user actions without using an _ICacheRefresher_, review and update your code using the documentation below.** -{% endhint %} - -## Retrieving and Adding items in the cache - -You can [update and insert items in the cache](updating-cache.md). - -## Refreshing/Invalidating cache - -### [ICacheRefresher](icacherefresher.md) - -The standard way to invalidate cache in Umbraco is to implement an `ICacheRefresher`. - -The interface consists of the following methods: - -* `Guid RefresherUniqueId { get; }` - * Which you'd return your own unique GUID identifier -* `string Name { get; }` - * The name of the cache refresher (informational purposes) -* `void RefreshAll();` - * This would invalidate or refresh all caches of the caching type that this `ICacheRefresher` is created for. For example, if you were caching `Employee` objects, this method would invalidate all `Employee` caches. -* `void Refresh(int Id);` - * This would invalidate or refresh a single cache for an object with the provided `int` id. -* `void Refresh(Guid Id);` - * This would invalidate or refresh a single cache for an object with the provided GUID id. -* `void Remove(int Id);` - * This would invalidate a single cache for an object with the provided `int` id. In many cases Remove and Refresh perform the same operation but in some cases `Refresh` doesn't remove/invalidate a cache entry, it might update it. `Remove` is specifically used to remove/invalidate a cache entry. - -_Some of these methods may not be relevant to the needs of your own cache invalidation so not all of them may need to perform logic._ - -There are 2 other base types of `ICacheRefresher` which are: - -* `ICacheRefresher` - this inherits from `ICacheRefresher` and provides a set of strongly typed methods for cache invalidation. This is useful when executing the method to invoke the cache refresher, when you have the instance of the object already since this avoids the overhead of retrieving the object again. - * `void Refresh(T instance);` - this would invalidate/refresh a single cache for the specified object. - * `void Remove(T instance);` - this would invalidate a single cache for the specified object. -* `IJsonCacheRefresher` - this inherits from `ICacheRefresher` but provides more flexibility if you need to invalidate cache based on more complex scenarios (for example, the [MemberGroupCacheRefresher](https://github.com/umbraco/Umbraco-CMS/blob/9f912aea0e4759a1fcea43d7469d3d4756b6fbe1/src/Umbraco.Core/Cache/MemberGroupCacheRefresher.cs)). - * `void Refresh(string jsonPayload)` - Invalidates/refreshes any cache based on the information provided in the JSON. The JSON value is any value that is used when executing the method to invoke the cache refresher. - -There are a couple of examples of `ICacheRefresher's` in the [core](https://github.com/umbraco/Umbraco-CMS/tree/9f912aea0e4759a1fcea43d7469d3d4756b6fbe1/src/Umbraco.Core/Cache). - -### Executing an ICacheRefresher - -To execute your `ICacheRefresher` you call these methods on the `DistributedCache` instance (the `DistributedCache` object exists in the `Umbraco.Cms.Core.Cache` namespace): - -* `void Refresh(Guid cacheRefresherId, Func getNumericId, params T[] instances)` - * This executes an `ICacheRefresher.Refresh(T instance)` of the specified cache refresher Id -* `void Refresh(Guid cacheRefresherId, int id)` - * This executes an `ICacheRefresher.Refresh(int id)` of the specified cache refresher Id -* `void Refresh(Guid cacheRefresherId, Guid id)` - * This executes an `ICacheRefresher.Refresh(Guid id)` of the specified cache refresher Id -* `void Remove(Guid refresherGuid, int id)` - * This executes an `ICacheRefresher.Remove(int id)` of the specified cache refresher Id -* `void Remove(Guid refresherGuid, Func getNumericId, params T[] instances)` - * This executes an `ICacheRefresher.Remove(T instance)` of the specified cache refresher Id -* `void RefreshAll(Guid refresherGuid)` - * This executes an `ICacheRefresher.RefreshAll()` of the specified cache refresher Id - -**So when do you use these methods to invalidate your cache?** - -This really comes down to what you are caching and when it needs to be invalidated. - -### What happens when an ICacheRefresher is executed? - -When an `ICacheRefresher` is executed via the `DistributedCache` a notification is sent out to all servers that are hosting your web application to execute the specified cache refresher. When not load balancing, this means that the single server hosting your web application executes the `ICacheRefresher` directly. However when load balancing, this means that Umbraco will ensure that each server hosting your web application executes the `ICacheRefresher` so that each server's cache stays in sync. - -## Events handling to refresh cache - -To use the extensions add a using to `Umbraco.Extensions`; You can then invoke them on the injected `DistributedCache` object. - -## IServerMessenger - -The server messenger broadcasts 'distributed cache notifications' to each server in the load balanced environment. The server messenger ensures that the notification is processed on the local environment. - -## Getting and clearing cached content - -[See our example on how to cache tags](examples/tags.md). - -## [ApplicationCache](application-cache.md) diff --git a/10/umbraco-cms/reference/cache/application-cache.md b/10/umbraco-cms/reference/cache/application-cache.md deleted file mode 100644 index aa6befa7022..00000000000 --- a/10/umbraco-cms/reference/cache/application-cache.md +++ /dev/null @@ -1,31 +0,0 @@ -# Accessing the cache - -You should always be doing this consistently with the best practices listed below. You shouldn't be using HttpRuntime.Cache or HttpContext.Current.Cache directly. Instead, you should always be accessing it via the AppCaches cache helper (`Umbraco.Cms.Core.Cache`). - -## Cache types - -The `AppCaches` which can be found in namespace `Umbraco.Cms.Core.Cache` contains types of cache: Runtime Cache, Request Cache and Isolated Caches. - -**Runtime Cache** is the most commonly used and is synonymous with HttpRuntime.Cache. **Request cache** is cache that exists only for the current request. This is synonymous with HttpContext.Current.Items and **isolated caches**. These are used by for example repositories, to ensure that each cached entity type has its own cache. When they have their own cache, lookups are fast and the repository does not need to search through all keys on a global scale. - -## Getting the AppCaches - -If you wish to use the AppCaches in a class, you need to use Dependency Injection (DI) in your constructor: - -```csharp -public class MyClass -{ - - private readonly IAppPolicyCache _runtimeCache; - private readonly IAppCache _requestCache; - private readonly IsolatedCaches _isolatedCaches; - - public MyClass(AppCaches appCaches) - { - _runtimeCache = appCaches.RuntimeCache; - _requestCache = appCaches.RequestCache; - _isolatedCaches = appCaches.IsolatedCaches; - } - -} -``` diff --git a/10/umbraco-cms/reference/cache/examples/README.md b/10/umbraco-cms/reference/cache/examples/README.md deleted file mode 100644 index c77fc7b4433..00000000000 --- a/10/umbraco-cms/reference/cache/examples/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Examples - -- [Setting up caching on the tags property](tags.md). diff --git a/10/umbraco-cms/reference/cache/examples/images/response-2.PNG b/10/umbraco-cms/reference/cache/examples/images/response-2.PNG deleted file mode 100644 index 812fc3ad56c..00000000000 Binary files a/10/umbraco-cms/reference/cache/examples/images/response-2.PNG and /dev/null differ diff --git a/10/umbraco-cms/reference/cache/examples/images/response.PNG b/10/umbraco-cms/reference/cache/examples/images/response.PNG deleted file mode 100644 index 147915c206e..00000000000 Binary files a/10/umbraco-cms/reference/cache/examples/images/response.PNG and /dev/null differ diff --git a/10/umbraco-cms/reference/cache/examples/tags.md b/10/umbraco-cms/reference/cache/examples/tags.md deleted file mode 100644 index 39cd973340b..00000000000 --- a/10/umbraco-cms/reference/cache/examples/tags.md +++ /dev/null @@ -1,210 +0,0 @@ ---- - -meta.Title: "Working with the runtime cache in Umbraco" -description: "Information on how to insert and delete from the runtime cache" ---- - -# Working with caching - -This article will show you how to insert and delete from the runtime cache. - -## Scenario - -For this example we're working with tags. On my site I have two tag properties: - -1) One on every page using the tag group `default` - -2) One on my blog posts using the tag group `blog` - -We're going to expose an endpoint that allows us to get the tags from each group. - -The tags from the `default` should be cached for a minute. The `blog` tags will be cached until site restart or if you publish a blog post node in the Backoffice. - -## Example - -Why work with tags? Because they're not cached by default.. which makes them ideal for demo purposes :) - -### TagService - -First we want to create our `CacheTagService`. In this example it's a basic class with one method (`GetAll`) that wraps Umbraco's `TagQuery.GetAllTags()`. - -```csharp -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Extensions; - -namespace Doccers.Core.Services.Implement -{ - public class CacheTagService : ICacheTagService - { - private readonly ITagQuery _tagQuery; - private readonly IAppPolicyCache _runtimeCache; - - public CacheTagService(ITagQuery tagQuery, AppCaches appCaches) - { - _tagQuery = tagQuery; - // Grap RuntimeCache from appCaches - // and assign to our private field. - _runtimeCache = appCaches.RuntimeCache; - } - - public IEnumerable GetAll( - string group, - string cacheKey, - TimeSpan? timeout = null) - { - // GetCacheItem will automatically insert the object - // into cache if it doesn't exist. - return _runtimeCache.GetCacheItem(cacheKey, () => - { - return _tagQuery.GetAllTags(group); - }, timeout); - } - } -} -``` - -As you can see we inherit from the `ICacheTagService` interface. All that has is: - -```csharp -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core.Models; - -namespace Doccers.Core.Services -{ - public interface ICacheTagService - { - IEnumerable GetAll( - string group, - string cacheKey, - TimeSpan? timeout = null); - } -} -``` - -The interface was created to better register it so we can use dependency injection. You can register your own classes like so: - -```csharp -using Doccers.Core.Services; -using Doccers.Core.Services.Implement; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Microsoft.Extensions.DependencyInjection; - -namespace Doccers.Core -{ - public class Composer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddScoped(); - } - } -} -``` - -Now you can inject `ICacheTagService` in any constructor in your project - wohooo! - -### API - -Now that we have our service it's time to create an endpoint where we can fetch the (cached) tags. - -```csharp -using System; -using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; -using Doccers.Core.Services; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Web.Common.Controllers; - - -namespace Doccers.Core.Controllers.Api -{ - public class TagsController : UmbracoApiController - { - private readonly ICacheTagService _tagService; - - // Dependency injection rocks! - public TagsController(ICacheTagService tagService) - { - _tagService = tagService; - } - - [HttpGet] - public IEnumerable GetDefaultTags() - { - // As mentioned earlier we want tags from "default" - // group to be cached for a minute. - return _tagService.GetAll("default", "defaultTags", - TimeSpan.FromMinutes(1)); - } - - [HttpGet] - public IEnumerable GetBlogTags() - { - // If you don't specify a TimeSpan the object(s) - // will be cached until manually removed or - // if the site restarts. - return _tagService.GetAll("blog", "blogTags"); - } - } -} -``` - -![`/umbraco/api/tags/getblogtags`](images/response.png) - -![`/umbraco/api/tags/getdefaulttags`](images/response-2.png) - -Everything should now work as expected when it comes to getting tags. However, if I go to my Backoffice and add a new tag to the `blog` group the changes aren't shown on the endpoint. Let's fix that. - -### Clearing cache on publish - -To clear the cache we need a notification handler in which we register to the `ContentPublishedNotification` event on the `ContentService`. This allows us to run a piece of code whenever you publish a node. - -```csharp -using System.Linq; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace Doccers.Core -{ - public class Notification : INotificationHandler - { - - private readonly IAppPolicyCache _runtimeCache; - - public Notification(AppCaches appCaches) - { - _runtimeCache = appCaches.RuntimeCache; - } - - public void Handle(ContentPublishedNotification notification) - { - - if (notification.PublishedEntities.Any(x => x.ContentType.Alias == "blogPost")) - { - _runtimeCache.ClearByKey("blogTags"); - } - } - } -} -``` - -Now that we have our notification we also need to register it. Add `builder.AddNotificationHandler();` to the `Compose` method in the `Composer` class so it becomes: - -```csharp -public void Compose(IUmbracoBuilder builder) -{ - builder.Services.AddScoped(); - - builder.AddNotificationHandler(); - -} -``` - -Awesome! Now we have set up caching on our tags - making the site a bit faster. :) diff --git a/10/umbraco-cms/reference/cache/icacherefresher.md b/10/umbraco-cms/reference/cache/icacherefresher.md deleted file mode 100644 index d91b9b86346..00000000000 --- a/10/umbraco-cms/reference/cache/icacherefresher.md +++ /dev/null @@ -1,16 +0,0 @@ ---- - - ---- - -# ICacheRefresher - -_This section describes what ICacheRefresher and ICacheRefresher<T> are and how to use them to invalidate your cache correctly including load balanced environments_ - -## What is an ICacheRefresher - -This interface has been in the Umbraco core for a significant period. However, it has really only been used to ensure that content cache is refreshed among all server nodes participating in a load balanced scenario. - -An `ICacheRefresher` is the primary method that invalidates *any* cache needing refreshment or removal. This applies regardless of a load balanced environment. - -There are now a few different types of `ICacheRefreshers` in the Umbraco core. It is important to understand the differences between them and how cache invalidation works across multiple server nodes. \ No newline at end of file diff --git a/10/umbraco-cms/reference/cache/iservermessenger.md b/10/umbraco-cms/reference/cache/iservermessenger.md deleted file mode 100644 index 1c473766769..00000000000 --- a/10/umbraco-cms/reference/cache/iservermessenger.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -needsV8Update: 'true' ---- - -# IServerMessenger - -Broadcasts distributed cache notifications to all servers of a load balanced environment. Also ensures that the notification is processed on the local environment. - -For a specified [ICacheRefresher](icacherefresher.md), the implemented methods will: - -* Notify the distributed cache -* Invalidate specified items -* Notify all servers of specified items removal -* Notify all servers of invalidation of a object -* Notify all servers of a global invalidation (clear the complete cache) diff --git a/10/umbraco-cms/reference/cache/updating-cache.md b/10/umbraco-cms/reference/cache/updating-cache.md deleted file mode 100644 index 94b302d61fd..00000000000 --- a/10/umbraco-cms/reference/cache/updating-cache.md +++ /dev/null @@ -1,40 +0,0 @@ -# Getting/Adding/Updating/Inserting Into Cache - -_This section describes how you should be getting/adding/updating/inserting items in the cache._ - -## Adding and retrieving items in the cache - -The recommended way to put data in and get data out is to use one of the many overloaded methods of: `GetCacheItem`. The `GetCacheItem` methods (all except one) are designed to "Get or Add" to the cache. The following retrieves an item from the cache and adds it if it doesn't already exist: - -```csharp -MyObject cachedItem = _appCaches.RuntimeCache.GetCacheItem("MyCacheKey", () => new MyObject()); -``` - -where `_appCaches` is injected as type `AppCaches`. - -Notice 2 things: - -* The `GetCacheItem` method is strongly typed and -* We are supplying a callback method which is used to populate the cache if it doesn't exist. - -The example above will retrieve a strongly typed object of `MyObject` from the cache with the key of "MyCacheKey". If the object doesn't exist in the cache, a new instance of MyObject `MyObject` be added to it with the same key. - -There are a couple of overloads of `GetCacheItem` allowing you to customize how your object is cached from cache dependencies to expiration times. - -To use this generic implementation, add the `Umbraco.Extensions` namespace to your code. - -### Retrieving an item from the cache without a callback - -One of the overloads of `GetCacheItem` doesn't specify a callback. This allows you to retrieve an item from the cache without populating it if it doesn't exist. - -An example of usage: - -```csharp -MyObject cachedItem = _appCaches.RuntimeCache.GetCacheItem("MyCacheKey"); -``` - -where `_appCaches` is injected as type `AppCaches`. - -### Inserting an item into the cache without retrieval - -Sometimes you might want to put something in the cache without retrieving it. In this case there is an `InsertCacheItem` method. This method will add or update the cache item specified by the key. If the item already exists in the cache, it will be replaced. diff --git a/10/umbraco-cms/reference/common-pitfalls.md b/10/umbraco-cms/reference/common-pitfalls.md deleted file mode 100644 index 6749b0fff8d..00000000000 --- a/10/umbraco-cms/reference/common-pitfalls.md +++ /dev/null @@ -1,374 +0,0 @@ ---- -meta.Title: Common Pitfalls and Anti-Patterns in Umbraco -description: Information on common Pitfalls and Anti-Patterns in Umbraco ---- - -# Common Pitfalls & Anti-Patterns - -This section describes many common pitfalls that developers fall into. Some of the anti-patterns mentioned here can bring your site to a grinding halt, cause memory leaks, or make your site unstable or perform poorly. Make sure you read this section - it might save your site. - -## Usage of Singletons and Statics - -Generally speaking, if you are writing software these days you should be using Dependency Injection principles. If you do this, you probably aren't using [Singletons](https://en.wikipedia.org/wiki/Singleton_pattern) or [Statics](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members) (and for the most part you shouldn't be!). Since Umbraco 9 comes with dependency injection out of the box, there really isn't any reason to use singletons or statics. It makes your code very difficult to test but more importantly using Singletons and Statics in your code makes it very hard to manage, APIs become leaky, and ultimately you'll end up with more problems than when you started. - -Dependency injection is available everywhere, and you can register your own services as well, additionally, some resources are available through properties on certain base classes. For example, all Razor views that Umbraco creates expose an `UmbracoHelper` property you can access through `@Umbraco`, as well as a `SmidgeHelper` property. The other base classes that expose some things you might need like `UmbracoContext` are things like `SurfaceController`, but even here the services are initially gotten through DI, and you can inject further Umbraco and custom services that you might need. - -For more information about consuming and registering your own dependencies have a look at the [Dependency Injection](using-ioc.md) documentation - -**Example of using base class properties gotten through DI:** - -```csharp -public class ContactFormSurfaceController : SurfaceController -{ - // The services are injected with DI and passed to the parent class - public ContactFormSurfaceController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult SubmitForm(ContactFormModel model) - { - // All normal form processing logic is left out of this example for brevity - // You can access all of these because they are properties of the base class, - // if you need something else you can inject it in the constructor. - - //Profiling logger - using (ProfilingLogger.TraceDuration("Start", "stop")) - { - // UmbracoContext - UmbracoContext.Content.GetById(1234); - } - - return Ok(); - } -} -``` - -So next time you are using a singleton pattern or a static, think "Why am I doing this?", "I'm using Dependency Injection, I should be injecting this instance into my class." - -## Static references to scoped instances (such as `UmbracoHelper`) - -**Example 1:** - -```csharp -public class BadApiController : UmbracoApiController -{ - // Note that this is static, that's bad - private static UmbracoHelper _umbracoHelper; - - public BadApiController(IUmbracoHelperAccessor umbracoHelperAccessor) - { - // Don't do this, this is bad - if (_umbracoHelper is null) - { - umbracoHelperAccessor.TryGetUmbracoHelper(out UmbracoHelper umbracoHelper); - _umbracoHelper = umbracoHelper; - } - } -} -``` - -This practice can cause memory leaks along with inconsistent data results when using this `_umbracoHelper` instance. - -**Why?** - -It's important to understand the difference between an object that has a Request based scope/lifespan and an object that has a Singleton/Application based scope/lifespan ... here's the gist: - -* Application scope - if an object has a singleton/application scope/lifespan, that means that this single object instance will exist for the lifetime of the application. The single instance will be shared by every thread that accesses it. Static variables will always be application lifespan. -* Request scope - The web world is made up of requests and each request has its own thread. When an object is in the scope of a Request it only survives as long as the web request survives. At the end of the web request, it may either be disposed of or cleared from memory by the garbage collector. Request scoped object instances are not accessed by every other thread in the application - **unless you do something like the above!** - -An example of a request-scoped instance is the `HttpContext`. This object exists for a single request and it definitely cannot be shared between other threads and especially not other request threads. This is because it is where the security information for a given user is stored! The `UmbracoContext` is also a request-scoped object - in fact, it relies directly on an instance of `HttpContext`. The `UmbracoHelper` is request-scoped as well. - -So... in the above example, the `UmbracoHelper` which has a request-scoped lifetime, will now be statically assigned to a variable, which means that this particular request-scoped object is now bound to an Application scope lifetime and will never go away. This could mean that under certain circumstances that an entire Umbraco cache copy is stuck in memory, or that the `Security` property of the context will be accessed by multiple threads but this now contains the security information for a user for another request! - -Additionally, since V9 comes with dependency injection out of the box, there's never really any reason to use static references, instead, you should always use inject your required resources, and let the DI container handle the lifetimes of the objects. - -## Querying with Descendants, DescendantsOrSelf - -It's not 100% bad that you use these queries, you need to understand the implications. Here's a particularly bad scenario: - -You have 10,000 content items in your tree and your tree structure is something like this: - -``` -- Root --- Home --- Blog (list view with 9495 nodes) --- Office Locations (list view with 500 nodes) --- About Us --- Contact Us -``` - -You create a menu on your Home page like: - -```csharp - -``` - -Which renders out: _Root, Home, Blog, Office Locations, About Us, Contact Us_ - -BUT!... this is going to perform most horribly. This is going to iterate over every single node in Umbraco, all 10,000 of them! - -This can be re-written as: - -```csharp - -``` - -In many cases, you might know that there is only ever going to be a small number of Descendants. If so then go nuts and use Descendants or DescendantsOrSelf. It's important to be aware of the implications of what you are writing. - -## Too much querying (Over querying) - -Querying content is not Free! Anytime you make a query or resolve a property value be aware that there is overhead involved. You could try to think about every query you make as an SQL call - you don't want to make too many otherwise the performance of your website is going to suffer. - -Here's a common pitfall that is seen. Let's continue the menu example, in this example, the menu is going to be rendered using the current page's root node: - -```csharp - -``` - -The syntax `@Model.Root()` is shorthand for doing this: `Model.AncestorOrSelf(1)` which means it is going to traverse up the tree until it reaches an ancestor node with a level of one. As mentioned above, traversing costs resources and in this example, there are 3x traversals being done for the same value. Instead, this can be rewritten as: - -```csharp -@{ - var root = Model.Root(); -} - -``` - -## Using the Services layer in your views - -The Services layer of Umbraco is for manipulating the business logic of Umbraco directly to/from the database. None of these methods should be used within your views and can have a very large impact on the performance and stability of your application. - -Your views should rely only on the read-only data services such as `UmbracoHelper`, `ITagQuery` and `IMemberManager` and the properties/methods that they expose. This ensures that the data being queried is fast (comes from cache) and that you aren't inadvertently making database changes. - -**For example**, when retrieving a content item in your views: - -```csharp -@using Umbraco.Cms.Core.Services -@inject IContentService _contentService - -@{ - // Services access in your views :( - var dontDoThis = _contentService.GetById(1234); - - // Content cache access in your views - var doThis = Umbraco.Content(1234); -} -``` - -If you are using services in your views, you should figure out why this is being done and, in most cases, remove this logic. - -## Using Umbraco content items for volatile data - -This is one of the worst Umbraco anti-patterns and could very well cause your site to perform ultra poorly. - -Umbraco's content should not be used for volatile data, Umbraco's APIs and the way Umbraco's data is persisted was never designed for this. If you need to store/write/track data that changes a lot you should use a custom database table or another service but not Umbraco content nodes. - -Some examples of what not to do are: - -* Hit counters to track the number of times your page has been viewed - use something like Google Analytics for this or a custom database table -* Creating new nodes for form submissions - this should be stored in a custom database table -* Importing lots of data into Umbraco content nodes that could be stored in a custom database table (i.e. it's not going to be edited). In some cases, this might be ok but many times we've seen bulk imports occur on an hourly/daily schedule which is generally unnecessary. - -## Processing during startup - -Umbraco allows you to run some initialization code during startup by using `UmbracoApplicationStartingNotification` or `UmbracoApplicationMainDomAcquiredNotification`, however, great care should be used to ensure that you are not slowing down application startup. You should be especially careful as a Package developer that you are not slowing down application startup since your package may end up being used for thousands of websites. - -In many cases, [initialization code can be done lazily instead of eagerly](https://msdn.microsoft.com/en-us/library/dd997286\(v=vs.110\).aspx). Instead of initialization everything you need as soon as the application starts you could execute your initialization code only when it is required. This can be achieved in various ways such as: - -* Using [`Lazy`](https://msdn.microsoft.com/en-us/library/dd642331\(v=vs.110\).aspx) and put the initialization logic in its callback -* Using [`LazyInitializer`](https://msdn.microsoft.com/en-us/library/system.threading.lazyinitializer\(v=vs.110\).aspx?f=255\&MSPPError=-2147217396) -* Putting logic in a property getter with a lock and setting a flag that it's processed -* Putting logic in a method with a lock and setting a flag that it's processed -* (there's plenty of ways) - -Even more important is that you ensure that the initialization logic only executes one time for the lifetime of the application even when your app domain is restarted. If your initialization logic creates a database table or something similar to that, where it should only be executed one time only. Then you should set a persistent flag (such as a file) to indicate to your own logic that the initialization code has already been executed and doesn't need to be done again. - -## Rebuilding indexes - -Far too often we've seen code in people's solutions that rebuild the Examine indexes (we've even seen this done on every request!). Rebuilding indexes can cause severe performance penalties and is not a recommended practice. Umbraco's and Examine's index management, index stability, and synchronization of the data in the index get better with every release. You should always ensure you are running the latest Umbraco and Examine versions if you are having trouble with your index data becoming out of sync with your Umbraco data. - -The primary reasons your data will become out of sync are: - -* Old version of Umbraco -* Rebuilding indexes and restarting your app domain at the same time (try to avoid this scenario!) - -It is not recommended to rebuild your indexes unless you absolutely need to and if you need to do this often then it is advised to determine why and to try to resolve the underlying problem. - -## Performing lookups and logic in Examine events - -There's a couple well known Examine events: `TransformingIndexValues` and `DocumentWriting`. Both of these events allow the developer to modify the data that is going into the Lucene index but many times we see developers Performing Service lookups in these methods. For example, using `IContentService.GetById(e.NodeId)` inside of these events could cause an `N + 1` problem. This is because these events are executed for every single document being indexed and if you are rebuilding an index, this will mean this logic will fire for every single document and media item going into each index ... That could mean a tremendous number of lookups and performance drain. - -Similarly, if you are executing other logic in these events that perform poorly, then anytime you save or publish content or media it will slow that process down. And if you rebuild an index then any slow code running in these events will cause the indexing to go ultra slow. - -## RenderTemplateAsync - -There is an API in Umbraco that should never be used unless you really know what you are doing. This API method is called `RenderTemplateAsync`. It allows you to be able to render a particular content item's template and get a `IHtmlEncodedString` in response. In some cases, this may be useful. Perhaps you want to send an email based on a content item and its template, but you must be very careful not to use this for purposes it is not meant to be used for. - -Generally speaking, this method should not be used for the normal rendering of content. If abused this could cause severe performance problems. For normal content rendering of module type data from another content item, you should use Partial Views instead. - -## Don't put logic inside your constructors - -Constructors should generally not perform any logic, they should set some parameter values, perform some null checks and perhaps validate some data but in most cases, they should not perform any logic. - -There are a few reasons why this can become a huge performance problem: - -* The consumer of an API doesn't expect that by creating an object that they should be worried about performance -* Creating an object can inadvertently happen a vast number of times, especially when using LINQ - -Here's an example of how this can go wrong very quickly: Your tree structure is something like this: - -``` -- Root --- Home ---- Recipes (node id = 3251, list view with 5000 nodes) ---- About Us ---- Contact Us -``` - -You have a custom model that looks like this: - -```csharp -public class RecipeModel : PublishedContentWrapped -{ - public RecipeModel(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content, publishedValueFallback) - { - RelatedRecipes = content - .Parent - .Children() - .Where(x => x.Value>("related") - .Contains(content.Id)); - - Votes = content.Value("votes"); - } - - public int Votes { get; private set; } - - public IEnumerable RelatedRecipes { get; private set; } -} -} -``` - -You then run the following code to show to show the favorites - -```csharp -@var recipeNode = Umbraco.TypedContent(3251); -@{ - var recipeNode = Umbraco.Content(1234); -} - -
    - @foreach (var recipe in recipeNode.Children - .Select(x => new RecipeModel(x, _publishedValueFallback)) - .OrderByDescending(x => x.Votes) - .Take(10)) - { -
  • @recipe.Name
  • - } -
-``` - -**Ouch!** To show the top 10 voted recipes's this will end up doing the following: - -* This will iterate over all 5000 Recipes -* This will create and allocate 5000 instances of `RecipeModel` -* For each `RecipeModel` created, this will traverse upwards, iterate all 5000 recipes then resolve property data for 2 properties - -This means that there is now an additional **5,000** new objects created and allocated in memory. The number of traversals/visits to each of these objects is now 5000 x 5000 = **25,000,000 (25 MILLION TIMES!)** - -_Side note: The other problem is the logic used to lookup related recipes is incredibly inefficient. Instead, each recipe should have a picker to choose its related recipe's and then each of those can be looked up by their ID. (There's probably a few other ways to achieve this too!)_ - -This leads us on to the next anti-pattern... - -## Don't eager load data, lazy load it instead - -The above example could be rewritten like this: - -```csharp - public class RecipeModel : PublishedContentWrapped - { - public RecipeModel(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content, publishedValueFallback) - {} - - private int? _votes; - public int Votes - { - get - { - // Lazy load the property value and ensure it's not re-resolved once it's loaded - return _votes ??= this.Value("votes"); - } - } - - // Just return the Ids, they can be resolved to IPublishedContent instances in the view or elsewhere, - // doesn't need to be in the model - this would also be bad if the model was cached since all of the - // related entities would end up in the cache too. - private List _related; - - public IEnumerable RelatedRecipes => _related ??= this.Value>("related").ToList(); - } -``` - -This is slightly better. but will still iterate over all Recipes so the number of traversals/visits to each of these objects is now **5000**. - -This is still not great though. There really isn't much reason to create a `RecipeModel`. This could be written like: - -```csharp -@{ - var recipeNode = Umbraco.Content(1234); -} - -
    - @foreach (var recipe in recipeNode.Children - .OrderByDescending(x => x.Value("votes")) - .Take(10)) - { -
  • @recipe.Name
  • - } -
-``` - -## Not caching expensive lookups - -Based on the above 2 points, you can see that iterating content with the traversal APIs ends up being very expensive. - -So what can we do to mitigate this? Unfortunately, there is no silver bullet that will solve all your performance issues, it will always depend on your specific scenario. One great tip though is to cache the IDs of the content you need in your critical code and then retrieve it from the cache by ID. For instance, if you need to render the same four pieces of content for your nav, then cache, or simply hardcode, the IDs of the content items and retrieve them with the ID using `Umbraco.Content`, this will always be much, much faster than trying to traverse your content tree and finding the content programmatically, since it will do a direct lookup in the cache, meaning that your code don't have to do thousands of traversals to get your content. - -## Be mindful about memory - -When memory is used, for instance creating 5,000 recipe models with a `Select` statement, Garbage Collection needs to occur and this turnover can cause performance problems. The more objects created, the more items allocated in memory, the harder the job is for the Garbage Collector == more performance problems. Even worse is when you allocate tons of items in memory and/or really large items in memory. They will remain in memory for a long time because they'll end up in something called "Generation 3" which the GC tries to ignore for as long as possible. It does so because it knows it's going to take a lot of resources to clean up! - -## Best practices when using Models Builder - -Extending models should be used to add stateless, local features to models. It should not be used to transform content models into view models or manage trees of content. You can read more about this in the [Understanding and Extending Models Builder documentation](templating/modelsbuilder/understand-and-extend.md). diff --git a/10/umbraco-cms/reference/configuration/README.md b/10/umbraco-cms/reference/configuration/README.md deleted file mode 100644 index cdd1cf8e0d6..00000000000 --- a/10/umbraco-cms/reference/configuration/README.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -meta.Title: Umbraco configuration -description: Information on configuring Umbraco ---- - -# Configuration - -In Umbraco 9+, we have moved away from the previous configuration using `.config` files, to instead using the .NET built-in configuration pattern. This means that there is no longer separate files for different configuration, the configuration is now primarily done using `IConfiguration` with different sources. E.g. The `appsettings.json` file. - -For more in depth information on the configuration pattern see Microsofts [Configuration in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0) article. - -## Managing Configuration - -You might not always want to have the configuration stored in the `appsettings.json` file, for instance, you might not want to have the admin password in the file if using the unattended feature. You might also want to use a specific set of configurations when developing your solution. To achieve this, the `IConfiguration` pattern can be used for this. - -With the configuration pattern the settings can be read from multiple different source, where some take precedence over other, you can configure you site with: - -1. The `appsettings.json` file -2. An `appsettings.{environment}.json` file -3. UserSecrets (Only when in development) -4. Environment variables -5. Command line arguments - -This list is in order of precedence, so the values from `appsettings.json` will only be used if they're not also defined in the environment variables. If they are, then the environment variable will be used instead. - -There is one caveat, to this precedence though, the `appsettings.{environment}.json` file will only be used if the current environment matches the name of the config file, for instance, the `appsettings.Development.json` file will only be used when the environment is set to development. - -### Using Environment Variables for Configuration - -It is not feasible to have an entire json file as an environment variable, and the `:` doesn't work with environment variables on all platforms, so instead a double underscore is used to create the hierarchy. - -As an example, if you want to set your unattended username, you would normally write it in the `appsettings.json` like so: - -```json -"Umbraco": { - "CMS": { - "Unattended": { - "UnattendedUserName": "A.N. Other" - } - } -} -``` - -As an environment variable it becomes a variable with the name `Umbraco__CMS__Unattended__UnattendedUserName` and a value of `A.N. Other`. - -### Using Command Line Arguments Configuration - -Like with environment variables, it's not feasible to use an entire JSON file as a command line argument. However, with the command line the `:` will work without issues, so each section of the hierarchy is separated with a `:` character. If we use the same example as above, you can achieve the same result by using the following when starting the site via the command line: - -`dotnet run Umbraco:CMS:Unattended:UnattendedUserName="A.N Other"` - -### Using UserSecrets for Configuration - -In the development environment it is possible to use UserSecrets for configuration, which is ideal for connection strings and similar settings that shouldn't be committed to source control. To use UserSecrets you need to first enable them for the project - this is done with the following command, issued within the directory that contains the `.csproj` file: - -`dotnet user-secrets init` - -Now it's possible to store the connection string with this command: - -`dotnet user-secrets set "ConnectionStrings:umbracoDbDSN" "CONNECTION_STRING_IN_HERE"` - -The name of the key is created in the same way as in the [Command Line](./#using-command-line-arguments-configuration) example above, and thus corresponds to this JSON chunk: - -```json -"ConnectionStrings": { - "umbracoDbDSN": "CONNECTION_STRING_IN_HERE" -} -``` - -## IntelliSense - -A great thing about `appsettings.json` is that it allows for intellisense with a schema file. For most editors this should work out of the box, without having to configure anything, since the schema is specified in the top of the file like so: `"$schema": "https://json.schemastore.org/appsettings.json"`. - -## Reading Configuration in Code - -You might need to read the configuration from your code. - -When reading the configuration you need to inject an [`IOptions<>`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.options.ioptions-1?view=dotnet-plat-ext-6.0) or [`IOptionsMonitor<>`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.options.ioptionsmonitor-1?view=dotnet-plat-ext-6.0) object into the class that needs it. Here is an example of how you would read the `Host` value from the SMTP settings contained within the global settings: - -```C# -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Configuration.Models; - -namespace MySite -{ - public class SomeClass - { - private GlobalSettings _globalSettings; - - public SomeClass(IOptions globalSettings) - { - _globalSettings = globalSettings.Value; - - var smtpHost = _globalSettings.Smtp.Host; - } - } -} -``` - -First off `using Microsoft.Extensions.Options` is added, to gain access to the `IOptions` type, and `using Umbraco.Cms.Core.Configuration.Models;` is added to get access to the `GlobalSettings` type. - -`IOptions` is then injected into the constructor of the class, where we can use the `Value` property to gain access to the actual settings object. - -Now we have a typed object containing our settings, so we can get the Host value by calling `_globalSettings.Smtp.Host`. - -To see what setting types you can access see the complete list below, each document corresponds to a settings type. - -## Configuration Options - -A complete list of all the configuration sections included in Umbraco, by default, can be seen here along with any keys they contain: - -* [Basic authentication settings](basicauthsettings.md) -* [Connection strings settings](connectionstringssettings.md) -* [Content settings](contentsettings.md) -* [Debug settings](debugsettings.md) -* [Examine settings](examinesettings.md) -* [Exception filter settings](exceptionfiltersettings.md) -* [Global settings](globalsettings.md) -* [Health checks settings](healthchecks.md) -* [Hosting settings](hostingsettings.md) -* [Imaging settings](imagingsettings.md) -* [Indexing settings](indexingsettings.md) -* [Install default data setting](installdefaultdatasettings.md) -* [Keep alive settings](keepalivesettings.md) -* [Logging settings](loggingsettings.md) -* [Maximum upload size settings](maximumuploadsizesettings.md) -* [Models builder settings](modelsbuildersettings.md) -* [NuCache settings](nucachesettings.md) -* [Package migration settings](packagemigrationsettings.md) -* [Plugins settings](pluginssettings.md) -* [Request handler settings](requesthandlersettings.md) -* [Rich text editor settings](richtexteditorsettings.md) -* [Runtime minification settings](runtimeminificationsettings.md) -* [Runtime settings](runtimesettings.md) -* [Security settings](securitysettings.md) -* [Serilog settings](serilog.md) -* [Tours settings](tourssettings.md) -* [Type finder settings](typefindersettings.md) -* [Unattended settings](unattendedsettings.md) -* [Web routing settings](webroutingsettings.md) - -## Configured by code - -* [FileSystemProviders](filesystemproviders.md) diff --git a/10/umbraco-cms/reference/configuration/basicauthsettings.md b/10/umbraco-cms/reference/configuration/basicauthsettings.md deleted file mode 100644 index 8ead3269398..00000000000 --- a/10/umbraco-cms/reference/configuration/basicauthsettings.md +++ /dev/null @@ -1,49 +0,0 @@ ---- - - -meta.Title: "Umbraco Basic Authentication Settings" -description: "Information on the basic authentication section" ---- - -# Basic Authentication Settings - -Allows you to configure the basic authentication settings for Umbraco. A basic authentication section fully populated with default values can be seen here: - -```json -"Umbraco": { - "CMS": { - "BasicAuth": { - "AllowedIPs": [], - "Enabled": false, - "RedirectToLoginPage": false, - "SharedSecret": { - "HeaderName": "X-Authentication-Shared-Secret", - "Value": null - } - } - } -} -``` -## AllowedIPs - -This is a comma-separated list of IP addresses you want to limit where the requests can come from. - -## Enabled - -If the value is set to `true`, the basic authentication is enabled. By default, the value is set to false. - -## RedirectToLoginPage - -If the value is set to `true`, instead of showing the basic authentication popup in the browser, the user is redirected to the login page. This is required for external logins to work. By default, the value is set to false. - -## SharedSecret - -A shared secret can be sent using an HTTP header to bypass the basic authentication. This can be valuable for server-to-server communication. - -### HeaderName - -The header name used to compare the shared secret. By default, the value is set to `X-Authentication-Shared-Secret`. - -### Value - -The value of the shared secret. Must be a string longer than 0 characters to be enabled. The default value is `null`. diff --git a/10/umbraco-cms/reference/configuration/connectionstringssettings.md b/10/umbraco-cms/reference/configuration/connectionstringssettings.md deleted file mode 100644 index c9c3d635592..00000000000 --- a/10/umbraco-cms/reference/configuration/connectionstringssettings.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -meta.Title: Umbraco Connection Strings Settings -description: Information on the connection strings settings section ---- - -# Connection strings settings - -The connection strings settings section contains the connection string to the database Umbraco will connect to. This section is similar to what is used by default in .NET Core. The important thing is that the key for the connection string Umbraco will use is `"umbracoDbDSN"`. It is also important to know that this section is outside the `Umbraco.CMS` section, and is therefore in the root of the config. - -An connection strings config can look like this: - -```json -{ - "ConnectionStrings": { - "umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", - "umbracoDbDSN_ProviderName": "Microsoft.Data.SQLite" - } -} -``` - -{% hint style="info" %} -We recommend using shared cache for SQLite when using Umbraco, as it provides better performance and consistency when multiple connections may access the database simultaneously. -{% endhint %} - -The connection string used here is an SQLite connection string, that will connect to a data in the file `Umbraco.sqlite.db` located in `/umbraco/Data` . - -Umbraco currently supports using either a Microsoft SQL Server or a SQLite database. Both of these options will have different connection strings. For more information about the specific connection strings, see: - -* [SQL Server 2019 connection strings](https://www.connectionstrings.com/sql-server-2019/) -* [SQLite connection strings](https://www.connectionstrings.com/sqlite/) - -{% hint style="info" %} -If you're using Umbraco 9 [SQL Server Compact database](https://www.connectionstrings.com/sql-server-compact/) is supported instead of SQLite. -{% endhint %} - -## Provider name - -Because Umbraco cannot determine the provider name from the connection string in all cases. Umbraco follows [Microsoft's convention](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0#connection-string-prefixes-1) for provider names, which involves specifying it as a postfix in the connection string name. diff --git a/10/umbraco-cms/reference/configuration/contentdashboard.md b/10/umbraco-cms/reference/configuration/contentdashboard.md deleted file mode 100644 index 370d5d844dc..00000000000 --- a/10/umbraco-cms/reference/configuration/contentdashboard.md +++ /dev/null @@ -1,41 +0,0 @@ ---- - - -meta.Title: "Umbraco Content Dashboard Settings" -description: "Information on the content dashboard settings section" ---- - -# Content Dashboard Settings - -Allows you to configure the Content Dashboard settings for Umbraco. - -```json -{ - "Umbraco": { - "CMS": { - "ContentDashboard": { - "AllowContentDashboardAccessToAllUsers": false, - "ContentDashboardPath": "cms", - "ContentDashboardUrlAllowlist": [] - } - } - } -} -``` - -## AllowContentDashboardAccessToAllUsers - -Gets a value indicating whether the Content Dashboard should be available to all users. - -When the value is `true` the dashboard is visible for all user groups. Otherwise, when the value is `false`, the default access rules for that dashboard will be in use. - -## ContentDashboardPath - -Gets the path to use when constructing the URL for retrieving data for the content dashboard. - -## ContentDashboardUrlAllowlist - -Gets the allowed addresses to retrieve data for the content dashboard. - -No addresses specified indicates that any URL is allowed. - diff --git a/10/umbraco-cms/reference/configuration/contentsettings.md b/10/umbraco-cms/reference/configuration/contentsettings.md deleted file mode 100644 index ccfe3241187..00000000000 --- a/10/umbraco-cms/reference/configuration/contentsettings.md +++ /dev/null @@ -1,260 +0,0 @@ -# Content Settings - -Content settings contains a handful of settings related to the content in the CMS. It includes settings such as allowed upload files, image settings, and much more. All the values in the content settings has default values, so all configuration is optional. - -The following snippet will give an overview of the keys and values in the content section including the default values: - -```json -"Umbraco": { - "CMS": { - "Content": { - "ContentVersionCleanupPolicy": { - "EnableCleanup": false, - "KeepAllVersionsNewerThanDays": 7, - "KeepLatestVersionPerDayForDays": 90 - }, - "AllowEditInvariantFromNonDefault": false, - "AllowedUploadFiles": [], - "AllowedMediaHosts": [], - "DisableDeleteWhenReferenced": false, - "DisableUnpublishWhenReferenced": false, - "DisallowedUploadFiles": ["ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd", "xamlx"], - "Error404Collection": [], - "HideBackOfficeLogo": false, - "Imaging": { - "ImageFileTypes": ["jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif"], - "AutoFillImageProperties": [ - { - "Alias": "umbracoFile", - "ExtensionFieldAlias": "umbracoExtension", - "HeightFieldAlias": "umbracoHeight", - "LengthFieldAlias": "umbracoBytes", - "WidthFieldAlias": "umbracoWidth" - } - ] - }, - "LoginBackgroundImage": "assets/img/login.jpg", - "LoginLogoImage": "assets/img/application/umbraco_logo_white.svg", - "MacroErrors": "Inline", - "Notifications": { - "DisableHtmlEmail": false, - "Email": null - }, - "PreviewBadge": "My HTML here]]>", - "ResolveUrlsFromTextString": false, - "ShowDeprecatedPropertyEditors": false - } - } -} -``` - -{% hint style="info" %} -From 10.4, `AllowedUploadFiles` & `DisallowedUploadFiles` is deprecated, they will still work, but will be removed in a future version! You can use `AllowedUploadedFileExtensions` & `DisallowedUploadedFileExtensions` instead! -{% endhint %} - -## Root level settings - -In the root level section, that is those without a separate sub section like Imaging, you can configure: - -### Allow Edit Invariant From Non-Default - -Invariant properties are properties on a multilingual site that are not varied by culture. This means that they share the same value across all languages added to the website. - -When the setting is set to `false` (default) the invariant properties that are shared between all languages can only be edited from the default language. This means you need access to the default language, in order to edit the property. - -When set to `true` the invariant properties will need to be unlocked before they can be edited. The lock exists in order to make it clear that this change will affect more languages. - -### Allowed upload files - -If greater control is required than available from the above, this setting can be used to store a list of file extensions. If provided, only files with these extensions can be uploaded via the backoffice. - -### Allowed media hosts - -By default, only relative URLs are allowed when getting URLs for resized images or thumbnails using the ImagesController. If you need absolute URLs you will have to add the allowed hosts to this list. The value could be `["umbraco.com", "www.umbraco.com", "our.umbraco.com"]`. - -### Disable delete when referenced - -This setting allows you to specify whether a user can delete content or media items that depend on other items. This also includes any descendants that have dependencies. Setting this to **true** will remove or disable the _Delete_ button. - -### Disable unpublish when referenced - -This setting allows you to specify whether or not users can unpublish content items that depend on other items or have descendants that have dependencies. Setting this to **true** will disable the _Unpublish_ button. - -### Disallowed upload files - -This setting consists of a list of file extensions that editors shouldn't be allowed to upload via the backoffice. - -### Error 404 collection - -In case of a 404 error (page not found) Umbraco can return a default page instead. This is set here. Notice you can also set a different error page, based on the current culture so a 404 page can be returned in the correct language. - -```json -"Error404Collection": [ - { - "ContentId": 1, - "Culture": "en-US" - } -] -``` - -The above example shows what you need to do if you only have a single site that needs to show a custom 404 page. You specify which node that should be shown when a request for a non-existing page is being made. You can specify the node in three ways: - -1. Enter the nodes **id** (`"ContentId": 1`) -2. Enter the node's **GUID** (`"ContentKey": "4f96ffdd-b969-46a8-949e-7935c41fabc0"`) -3. Enter the XPath to find the node (`"ContentXPath": "/root/Home//TextPage[@urlName = 'error404'"`) - -{% hint style="info" %} -* Ids are usually local to the specific solution (so won't point to the same node in two different environments if you're using Umbraco Cloud). -* GUIDs are universal and will point to the same node on different environments, provided the content was created in one environment and deployed to the other(s). -* When using XPath, there is no "context" (like, you can't find the node based on "currentPage") so needs to be a global absolute path. -{% endhint %} - -If you have multiple sites, with different cultures, setup in your tree then you will need to setup the errors section like below: - -```json -"Error404Collection": [ - { - "ContentId": 1, - "Culture": "default" - }, - { - "ContentId": 200, - "Culture": "en-US" - }] -``` - -If you have more than two sites and forget to add a 404 page and a culture, the default page will act as fallback. Same happens if you for some reason forget to define a hostname on a site. - -### Hide backoffice logo - -This setting can be used to hide the Umbraco logo in backoffice. - -### Login background image - -You can specify your own background image for the login screen here. The image will automatically get an overlay to match backoffice colors. This path is relative to the `wwwroot/umbraco` path. The default location is: `wwwroot/umbraco/assets/img/installer.jpg`. - -### Login logo image - -You can specify your own image for the small logo in the top left corner of the login screen. This path is relative to the `wwwroot/umbraco` path. The default location is: `wwwroot/umbraco/assets/img/application/umbraco_logo_white.svg`. - -### Macro errors - -This setting allows you to specify how errors in macros should be handled. - -Options: - -* Inline - Default Umbraco behavior, show an inline error within the macro but allow the page to continue rendering. -* Silent - Silently suppress the error and do not display the offending macro. -* Throw - Throw an exception. -* Content - Silently suppress the error, and display custom content reported in the error event args. - -### Preview badge - -This allows you to customize the preview badge being shown when you're previewing a node. - -```json -"PreviewBadge": "In Preview Mode - click to end]]>" -``` - -### Resolve urls from text string - -This setting is used when you're running Umbraco in virtual directories. Setting this to true can increase render time for pages with a large number of links. However, this is required if Umbraco is running in a virtual directory. - -### Show deprecated property editors - -This setting is used for controlling whether or not the Data Types marked as obsolete should be visible when creating new Data Types. - -By default this is set to `false`. To make the obsolete data types visible in the dropdown change the value to `true`. - -## ContentVersionCleanupPolicy - -The global settings for the scheduled job which cleans historic content versions. These settings can be overridden per Document Type. - -Current draft and published versions will never be removed, nor will individual content versions which have been marked as "preventCleanup". - -See [Content Version Cleanup](../../fundamentals/data/content-version-cleanup.md) for more details on overriding configuration and preventing cleanup of specific versions. - -```json -"ContentVersionCleanupPolicy": { - "EnableCleanup": false, - "KeepAllVersionsNewerThanDays": 7, - "KeepLatestVersionPerDayForDays": 90 -} -``` - -If you don't wish to retain content versions except for the current ones, you can set both of the "keep" settings values to 0. After doing this, the next time the scheduled job runs (hourly) all non-current versions (except those marked "prevent cleanup") will be removed. - -### EnableCleanup - -When `true` a scheduled job will delete historic content versions that are not kept according to the policy every hour. - -When `false`, the scheduled job will never delete any content versions regardless of overridden settings for a Document Type. - -This defaults to `false` when not set in the configuration which will be the case for those upgrading from v9.0.0. However, the dotnet new template will supply an appsettings.json with the value set to true for all sites starting from Umbraco 9.1.0. - -### KeepAllVersionsNewerThanDays - -All versions that fall in this period will be kept. - -### KeepLatestVersionPerDayForDays - -For content versions that fall in this period, the most recent version for each day is kept. All previous versions for that day are removed unless marked as preventCleanup. - -This variable is independent of `KeepAllVersionsNewerThanDays`, if both were set to the same value `KeepLatestVersionPerDayForDays` would never apply as `KeepAllVersionsNewerThanDays` is considered first. - -## Imaging - -This section is used for managing how Umbraco handles images, allowed attributes and, which properties of an image that should be automatically updated on upload. - -```json -"Imaging": { - "ImageFileTypes": ["jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif"], - "AutoFillImageProperties": { - "Alias": "umbracoFile", - "WidthFieldAlias": "umbracoWidth", - "HeightFieldAlias": "umbracoHeight", - "LengthFieldAlias": "umbracoBytes", - "ExtensionFieldAlias": "umbracoExtension" - } -} -``` - -Let's break it down. - -### ImageFileTypes - -This is a separated list of accepted image formats - -### AutoFillImageProperties - -You can define what properties should be automatically updated when an image is being uploaded. This means that if you decide to rename the default **umbracoWidth** and **umbracoHeight** properties the values in **`"WidthFieldAlias"`** and **`"HeightFieldAlias"`** need to be updated. This needs to happen in order to automatically populate the values when the image is being uploaded. - -### Custom media document - -If you need to create a custom Media Type to handle images you need to add another object using the custom Media Type alias. Like below. Keep in mind that the width and height attributes have also been changed in this example. - -```json -"Imaging": { - "ImageFileTypes": ["jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif"], - "AutoFillImageProperties": [ - { - "Alias": "umbracoFile", - "WidthFieldAlias": "umbracoWidth", - "HeightFieldAlias": "umbracoHeight", - "LengthFieldAlias": "umbracoBytes", - "ExtensionFieldAlias": "umbracoExtension" - }, - { - "Alias": "customImage", - "WidthFieldAlias": "width", - "HeightFieldAlias": "height", - "LengthFieldAlias": "umbracoBytes", - "ExtensionFieldAlias": "umbracoExtension" - } - ] -} -``` - -## Notifications - -Umbraco can send out email notifications. To set the SMTP server used to send the emails, edit the standard Simple Mail Transfer Protocol (SMTP) section in the global section. See the [Global settings](globalsettings.md) article for more information. diff --git a/10/umbraco-cms/reference/configuration/datatypes.md b/10/umbraco-cms/reference/configuration/datatypes.md deleted file mode 100644 index 9bbf649a95d..00000000000 --- a/10/umbraco-cms/reference/configuration/datatypes.md +++ /dev/null @@ -1,34 +0,0 @@ ---- - -meta.Title: "Umbraco Data Types Settings" -description: "Information on the data types settings section" ---- - -# Data Types Settings - -Allows you to configure the behavior of data types. - -```json -{ - "Umbraco": { - "CMS": { - "DataTypes": { - "CanBeChanged": "True" - } - } - } -} -``` - -## CanBeChanged - -Gets or sets a value indicating if data types can be changed after they've been used. - -Valid values: - -- `"True"` - - Allows data types to be changed after creation. This can lead to data on content is not valid on the Data Type. -- `"False"` - - Disallow Data Type changes. (Recommended value, unless you really know what you are doing) -- `"FalseWithHelpText"` - - Disallow Data Type changes, but show the users a help text so they understand why. diff --git a/10/umbraco-cms/reference/configuration/debugsettings.md b/10/umbraco-cms/reference/configuration/debugsettings.md deleted file mode 100644 index aaac9ae7137..00000000000 --- a/10/umbraco-cms/reference/configuration/debugsettings.md +++ /dev/null @@ -1,31 +0,0 @@ ---- - - -meta.Title: "Umbraco Debug Settings" -description: "Information on debug settings section" ---- - -# Debug settings - -This section contains configurations regarding debugging, and should therefore only be used in development. - -The debug section has two settings you can configure, `"LogIncompletedScopes"` and `"DumpOnTimeoutThreadAbort"`, both of these are false by default: - -```json -"Umbraco": { - "CMS": { - "Debug": { - "DumpOnTimeoutThreadAbort": false - "LogIncompletedScopes": false, - } - } -} -``` - -## Log incompleted scopes - -If this value is set to true, any scope that gets disposed without first being completed will trigger a log entry containing the stacktrace. - -## DumpOnTimeoutThreadAbort - -If this value is set to true, a memory dump will be taken if a thread aborts due to a timeout. This dump will be saved to `/umbraco/Data/MiniDump`. diff --git a/10/umbraco-cms/reference/configuration/examinesettings.md b/10/umbraco-cms/reference/configuration/examinesettings.md deleted file mode 100644 index a5d24dc1b49..00000000000 --- a/10/umbraco-cms/reference/configuration/examinesettings.md +++ /dev/null @@ -1,28 +0,0 @@ ---- - - -meta.Title: "Umbraco Examine Settings" -description: "Information on the Examine settings section" ---- - -# Examine settings - -Since the majority of Examine configuration takes place in code, this section is small and contains only one setting to change: `LuceneDirectoryFactory`. This setting allows you to change the behavior of the `ExamineIndexes` directory. - -This section has a default value, and does not need to be configured, configuring Examine might look something like this: - -```json -"Umbraco": { - "CMS": { - "Examine": { - "LuceneDirectoryFactory": "Default" - } - } -} -``` - -This is how Examine is configured by default. There is three different types of Lucene directory factories: - -* `Default` - The index will operate from the default location: `umbraco/Data/TEMP/ExamineIndexes` -* `SyncedTempFileSystemDirectoryFactory` - The index will operate on a local index created in the processes %temp% location and will replicate back to main storage in `umbraco/Data/TEMP/ExamineIndexes` -* `TempFileSystemDirectoryFactory` - The index will operate only in the processes %temp% directory location diff --git a/10/umbraco-cms/reference/configuration/exceptionfiltersettings.md b/10/umbraco-cms/reference/configuration/exceptionfiltersettings.md deleted file mode 100644 index b475debd0de..00000000000 --- a/10/umbraco-cms/reference/configuration/exceptionfiltersettings.md +++ /dev/null @@ -1,23 +0,0 @@ ---- - - -meta.Title: "Umbraco Exception Filter Settings" -description: "Information on the exception filter settings section" ---- - -# Exception filter settings - -This section allows you to disable the `ModelBindingExceptionFilter`, this filter is only enable if the models builder mode is set to `InMemoryAuto`. This filter will return a redirect to the page being loaded after one second, if a `ModelsBindingException` or `InvalidCastException` occurs. The reason for this filter is that a page might be requested at the same time as the content type has been changed. If this occurs, the new model might not have been generated and loaded yet. This filter will take care of this. - -By default this filter is enabled, but will be ignored if the mode is not `InMemoryAuto`. To manually disable the filter add the `"ExceptionFilter"` section to your config with the `"Disabled"` key set to `true` like so: - -```json -"Umbraco": { - "CMS": { - "ExceptionFilter": { - "Disabled": true - } - } -} -``` - diff --git a/10/umbraco-cms/reference/configuration/filesystemproviders.md b/10/umbraco-cms/reference/configuration/filesystemproviders.md deleted file mode 100644 index 2f074636198..00000000000 --- a/10/umbraco-cms/reference/configuration/filesystemproviders.md +++ /dev/null @@ -1,191 +0,0 @@ ---- - - -meta.Title: "FileSystemProviders in Umbraco" -description: "Information on FileSystemProviders and how to configure them in Umbraco" ---- - -# FileSystemProviders Configuration - -Filesystem providers are configured via code, you can either configure it in a composer, or in the `Startup.cs` file. - - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Infrastructure.DependencyInjection; -using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; - -namespace FilesystemProviders; - -public class FilesystemComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) => - builder.SetMediaFileSystem(factory => - { - IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); - var folderLocation = "~/CustomMediaFolder"; - var rootPath = hostingEnvironment.MapPathWebRoot(folderLocation); - var rootUrl = hostingEnvironment.ToAbsolute(folderLocation); - - return new PhysicalFileSystem( - factory.GetRequiredService(), - hostingEnvironment, - factory.GetRequiredService>(), - rootPath, - rootUrl); - }); -} -``` - -By default Umbraco will save Media in a folder called `/media` within the webroot on the Physical file system. The code snippet above will change the location to instead save the media in a folder called `/CustomMediaFolder` within the webroot. - -The media provider can be of many types, for example in case you want to store media on Azure, Amazon or even DB. But the provider that comes by default with the installation of Umbraco is the `PhysicalFileSystem` provider. - -## PhysicalFileSystem Configuration - -The physical file system provider manages the interaction of Umbraco with the local file system. It can be configured for two different scenarios: - - - Media files stored inside a virtual folder of the site - - Media files stored somewhere else outside of the site and accessed via a custom URL - -### Virtual Folder - -To configure the PhysicalFileSystem for a virtual folder, create a new filesystem with a root path and URL within the wwwroot folder. Refer to the example above and [Extending FileSystemProviders](../../extending/filesystemproviders/) for more information. - -### Physical path -There are a few more steps involved if you want to store the media files in a separate folder outside the webroot. - -First you must register the folder as a static file provider in your `Startup.cs` file like so: - -```C# -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - {...} - - app.UseStaticFiles(new StaticFileOptions - { - FileProvider = new PhysicalFileProvider(Path.Combine("C:", "storage", "umbracoMedia")), - RequestPath = "/CustomPath" - }); -} -``` - -Now you can register the folder as the media filesystem - -```C# -using System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Infrastructure.DependencyInjection; - -namespace FilesystemProviders -{ - public class FilesystemComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.SetMediaFileSystem((factory) => - { - IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); - var rootPath = Path.Combine("C:", "storage", "umbracoMedia"); - var rootUrl = hostingEnvironment.ToAbsolute("/CustomPath"); - - return new PhysicalFileSystem( - factory.GetRequiredService(), - hostingEnvironment, - factory.GetRequiredService>(), - rootPath, - rootUrl); - }); - } - } -} -``` - -This is much the same as when you register it within the wwwroot with a virtual folder. The only difference is that now you provide an absolute root path and root URL to the physical filesystem. - - - `rootPath` is the full filesystem path where you want media files to be stored. It has to be rooted, must use directory separators (`\`) and must not end with a separator. For example, `Z:` or `C:\path\to\folder` or `\\servername\path`. - - `rootUrl` is the URL where the files will be accessible from. It must use URL separators (`/`) and must not end with a separator. It can either be a folder, like `/UmbracoMedia`, in which case it will considered as subfolder of the main domain (`example.com/UmbracoMedia`) or can be a fully qualified URL, with also domain name and protocol (for ex `http://media.example.com/media`). - -For more information see [Extending FileSystemProviders](../../extending/filesystemproviders/). - -## Custom providers - -To store media files in different systems, the type of provider must be changed. You can learn [how to build a custom filesystem provider](../../extending/filesystemproviders/README.md#custom-file-systems-ifilesystem) in the Extending Umbraco section. - -{% hint style="info" %} -At the moment when a file is saved, its full URL is stored as node property. This means that a configuration change will not apply to pre-existing media files but only to the ones saved after that. - -If you want all your media files in the same location, you have to copy all pre-existing files to the new path. Additionally, you need to update the path property of the media item to the new URL. This can be either directly inside the database or by using the `MediaService`. -{% endhint %} - -## Get the contents of a file as a stream - -The recommended approach to obtain a file's content as a stream is to utilize the `MediaFileManager`. It is advised to avoid reading the file directly from the server using methods like `Server.MapPath`. This will ensure that, regardless of the file system provider, the stream will be returned correctly. TThis example demonstrates using MediaFileManager to validate file existence and stream it back from a controller. - -```csharp -using System.IO; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.StaticFiles; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Website.Controllers; - -namespace FilesystemProviders -{ - public class MediaController : SurfaceController - { - private readonly MediaFileManager _mediaFileManager; - private readonly IHostingEnvironment _hostingEnvironment; - - public MediaController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider, - MediaFileManager mediaFileManager, - IHostingEnvironment hostingEnvironment) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - _mediaFileManager = mediaFileManager; - _hostingEnvironment = hostingEnvironment; - } - - public IActionResult Index(string id, string file) - { - var path = _hostingEnvironment.MapPathWebRoot($"/media/{id}/{file}"); - - if (_mediaFileManager.FileSystem.FileExists(path)) - { - var stream = _mediaFileManager.FileSystem.OpenFile(path); - stream.Seek(0, SeekOrigin.Begin); - - var provider = new FileExtensionContentTypeProvider(); - string contentType; - if (!provider.TryGetContentType(file, out contentType)) - { - contentType = "application/octet-stream"; - } - - return new FileStreamResult(stream, contentType); - } - - return new NotFoundResult(); - } - } -} -``` diff --git a/10/umbraco-cms/reference/configuration/globalsettings.md b/10/umbraco-cms/reference/configuration/globalsettings.md deleted file mode 100644 index 3ef6dce71e6..00000000000 --- a/10/umbraco-cms/reference/configuration/globalsettings.md +++ /dev/null @@ -1,341 +0,0 @@ ---- - -meta.Title: Umbraco Global Settings -description: Information on the global settings section ---- - -# Global Settings - -Global settings contains at set of global settings for the CMS such as default UI language, reserved urls, and much more. All of these, except for SMTP settings contains default values, meaning that all configuration is optional, unless you wish to send emails from your site. - -The following snippet contains all the available options, with default values, and some example values for the required keys `From`, `Host` and `Port` keys of the SMTP settings: - -{% tabs %} -{% tab title="Latest version" %} -```json -"Umbraco": { - "CMS": { - "Global": { - "ReservedUrls": "~/.well-known,", - "ReservedPaths": "~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/,", - "TimeOut": "00:20:00", - "DefaultUILanguage": "en-US", - "HideTopLevelNodeFromPath": true, - "UseHttps": false, - "VersionCheckPeriod": 7, - "IconsPath": "~/umbraco/assets/icons", - "UmbracoCssPath": "~/css", - "UmbracoScriptsPath": "~/scripts", - "UmbracoMediaPath": "~/media", - "UmbracoMediaPhysicalRootPath": "X:/Shared/Media", - "InstallMissingDatabase": false, - "DisableElectionForSingleServer": false, - "DatabaseFactoryServerVersion": "SqlServer.V2019", - "MainDomLock": "FileSystemMainDomLock", - "MainDomKeyDiscriminator": "", - "Id": "184a8175-bc0b-43dd-8267-d99871eaec3d", - "NoNodesViewPath": "~/umbraco/UmbracoWebsite/NoNodes.cshtml", - "SanitizeTinyMce": false, - "Smtp": { - "From": "person@umbraco.dk", - "Host": "localhost", - "Port": 25, - "SecureSocketOptions": "Auto", - "DeliveryMethod": "Network", - "PickupDirectoryLocation": "", - "Username": "person@umbraco.dk", - "Password": "SuperSecretPassword" - }, - "DatabaseServerRegistrar": { - "WaitTimeBetweenCalls": "00:01:00", - "StaleServerTimeout": "00:02:00" - }, - "DatabaseServerMessenger": { - "MaxProcessingInstructionCount": 1000, - "TimeToRetainInstructions": "2.00:00:00", - "TimeBetweenSyncOperations": "00:00:05", - "TimeBetweenPruneOperations": "00:01:00" - }, - "DistributedLockingMechanism": "", - "DistributedLockingReadLockDefaultTimeout": "00:01:00", - "DistributedLockingWriteLockDefaultTimeout": "00:00:05", - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```json -"Umbraco": { - "CMS": { - "Global": { - "ReservedUrls": "~/.well-known,", - "ReservedPaths": "~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/,", - "TimeOut": "00:20:00", - "DefaultUILanguage": "en-US", - "HideTopLevelNodeFromPath": false, - "UseHttps": false, - "VersionCheckPeriod": 7, - "UmbracoPath": "~/umbraco", - "IconsPath": "~/umbraco/assets/icons", - "UmbracoCssPath": "~/css", - "UmbracoScriptsPath": "~/css", - "UmbracoMediaPath": "~/media", - "UmbracoMediaPhysicalRootPath": "X:/Shared/Media", - "InstallMissingDatabase": false, - "DisableElectionForSingleServer": false, - "DatabaseFactoryServerVersion": "SqlServer.V2019", - "MainDomLock": "MainDomSemaphoreLock", - "MainDomKeyDiscriminator": "", - "Id": "184a8175-bc0b-43dd-8267-d99871eaec3d", - "NoNodesViewPath": "~/umbraco/UmbracoWebsite/NoNodes.cshtml", - "SqlWriteLockTimeOut": "00:00:05", - "SanitizeTinyMce": false, - "Smtp": { - "From": "person@umbraco.dk", - "Host": "localhost", - "Port": 25, - "SecureSocketOptions": "Auto", - "DeliveryMethod": "Network", - "PickupDirectoryLocation": "", - "Username": "person@umbraco.dk", - "Password": "SuperSecretPassword" - }, - "DatabaseServerRegistrar": { - "WaitTimeBetweenCalls": "00:01:00", - "StaleServerTimeout": "00:02:00" - }, - "DatabaseServerMessenger": { - "MaxProcessingInstructionCount": 1000, - "TimeToRetainInstructions": "2.00:00:00", - "TimeBetweenSyncOperations": "00:00:05", - "TimeBetweenPruneOperations": "00:01:00" - } - } - } -} -``` -{% endtab %} -{% endtabs %} - -## Root level settings - -In the root level section, that is those without a separate sub section like SMTP, you can configure - -### Reserved urls - -A comma-separated list of files to be left alone by Umbraco, these files will be served, and the Umbraco request pipeline will not be triggered. - -### Reserved paths - -A comma-separated list of all the folders in your directory to be left alone by Umbraco. If you have folders with custom files, add them to this setting to make sure Umbraco leaves them alone. - -{% hint style="warning" %} Adding additional values to the Reserves URLs and Reserved Paths will overwrite default/current values. This causes performance issues as well. {% endhint %} - -### Timeout - -Configures the number of minutes without any requests being made before the Umbraco user will be required to re-login. Any backoffice request will reset the clock. The format is HH:MM:SS. - -### Default UI language - -The default language to use in the backoffice if a user isn't explicitly assigned one. - -### Hide top level nodes from path - -If you are running multiple sites, you don't want the top level node in your URL and can disable it with this setting. - -### Use https - -Makes sure that all of the requests in the backoffice are called over HTTPS instead of HTTP when set to true. - -### Version check period - -When this value is set above 0, the backoffice will check for a new version of Umbraco every 'x' number of days where 'x' is the value defined for this setting. Set this value to 0 to never check for a new version. - -### Icons path - -By adding this value you can specify a new/different folder for storing your icon resources. It's important to be aware of NetCore's limitations regarding serving static file content. By default, static content will only be served from the `wwwroot` folder. - -### Umbraco CSS path - -By adding this you can specify a new/different folder for storing your CSS files, and still be able to edit them within Umbraco. It's also important to be aware of NetCores limitations regarding serving static file content here as well, by default, static content will only be served from the wwwroot folder. For more info see [Extending filesystem](../../extending/filesystemproviders/) - -### Umbraco scripts path - -By adding this you can specify a new/different folder for storing your script/js files, and still be able to edit them within Umbraco. It's also important to be aware of NetCores limitations regarding serving static file content here as well, by default, static content will only be served from the wwwroot folder. For more info see [Extending filesystem](../../extending/filesystemproviders/) - -### Umbraco media path - -By adding this you can specify a new/different folder for storing your media files, and still be able to edit them within Umbraco. It's also important to be aware of NetCores limitations regarding serving static file content here as well, by default, static content will only be served from the wwwroot folder. For more info see [Extending filesystem](../../extending/filesystemproviders/) - -### Umbraco media physical root path - -By adding this you can specify a new/different folder for storing your media files elsewhere on the server. Unlike `UmbracoMediaPath`, this does not change the relative path that media is served from (e.g. /media) but allows for files to be stored **outside** of the wwwroot folder. Both relative paths (../../Shared/Media) and absolute server paths (X:/Shared/Media) are supported. For more info see [Extending filesystem](../../extending/filesystemproviders/) - -### Install missing database - -This is not a setting that commonly needs to be configured. - -If enabled Umbraco will try to automatically install the database when it's missing. This is primarily used in conjunction with unattended installs. - -### Disable election for single server - -This is not a setting that commonly needs to be configured. - -This value is primarily used on Umbraco Cloud for a small startup performance optimization. When this is true, the website instance will automatically be configured to not support load balancing and the website instance will be configured to be the 'primary' server for scheduling so no [primary election](../../fundamentals/setup/server-setup/load-balancing/file-system-replication.md) occurs. This will save 1 database call during startup. - -### Database factory version - -This is not a setting that commonly needs to be configured. - -This setting is used to specify which sql server version that the database is running, this setting is only required if you use SqlServer 2008, if this is the case set the setting to `"SqlServer.V2008"` - -### Main dom lock - -Specifies the implementation of IMainDomLock to be used. - -`IMainDomLock` is used to synchronize access to resources like the Lucene indexes. - -Available options: - -* `"FileSystemMainDomLock"`- Available cross-platform, uses lock files written to LocalTempPath to control acquisition of MainDom status. -* `"MainDomSemaphoreLock"` - Windows only, uses a named system Semaphore with a `maximumCount` of 1 to control acquisition of MainDom status. -* `"SqlMainDomLock"` - Available cross-platform, uses the database to control acquisition of MainDom status. - -The default implementation unless configured otherwise is `FileSystemMainDomLock`. - -### Main dom key discriminator - -For advanced use cases e.g. deployment slot swapping on Azure app services. - -When using SqlMainDomLock a MainDomKey is used to identify an instance of a running application. - -The MainDomKey is by default comprised of the server's machine name & the application id. - -This is generally all that is required to control MainDom status as starting a new process for the same application on the same server will result in a matching MainDomKey. This will then require that an existing instance yields MainDom status to the new process. - -Deployment slots for a given Azure App Service share the same machine name. Without additional configuration, they will share a MainDomKey and therefore compete for MainDom status. This can be undesirable if attempting to deploy to a deployment slot followed by a swap with the production slot as once traffic has switched to the new instance the old production instance reboots and can re-acquire MainDom status. See [What happens during a swap](https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots#what-happens-during-a-swap). - -To prevent this from occurring you can specify a MainDomKeyDiscriminator which should be set as a slot-specific configuration to prevent the slots from competing for MainDom status. - -It's worth noting that during the swap operation there is a period where both instances will share the same configuration and at this point, the old instance will yield MainDom status to the new instance. - -### Main dom release signal polling interval - -Gets or sets the duration (in milliseconds) for which the MainDomLock release signal polling task should sleep. The default value is 2000ms. - -### Id - -This setting doesn't need to be configured. - -This setting contains a unique ID used to identify your project, and is populated the first time your site runs, you shouldn't change this setting. - -### No nodes view path - -This setting specifies what view to render when there is no content on the site. - -## SMTP settings - -By adding this settings to the appsettings.json you will be able to send out emails from your Umbraco installation. This could be notifications emails if you are using content workflow, or you are using Umbraco Forms you also need to specify SMTP settings to be able use the email workflows. The forgot password function from the backoffice also needs a SMTP server to send the email with the reset link. - -### From - -Specifies the default address emails will be sent from, this setting may be overridden some place, such as when inviting a user, where the email of the user sending the invite will be used instead. The format of the address follows the RFC 822 standard so you can include a friendly name using the format `"Friendly Name "` - -### Host - -Address of the SMTP host used to send the email from. - -### Port - -The port of the SMTP host, port 25 is a common port for SMTP. - -### Username - -The username used to authenticate with the specified SMTP server, when sending an email. - -### Password - -The password used to authenticate with the specified SMTP server, when sending an email. - -### Secure socket options - -Allows you to specify what security should be used for the connection sending the email. - -The options are: - -* None - No SSL or TLS encryption should be used. -* Auto - Allow the IMailService to decide which SSL or TLS options to use (default). If the server does not support SSL or TLS, then the connection will continue without any encryption. -* SslOnConnect - The connection should use SSL or TLS encryption immediately. -* StartTls - Elevates the connection to use TLS encryption immediately after reading the greeting and capabilities of the server. If the server does not support the STARTTLS extension, then the connection will fail and a NotSupportedException will be thrown. -* StartTlsWhenAvailable - Elevates the connection to use TLS encryption immediately after reading the greeting and capabilities of the server, but only if the server supports the STARTTLS extension. - -### Delivery method - -Specifies what delivery method should be used for emails, most of the time you'd want to use the default `"Network"` option to send emails over the network. It might be useful during development to use `"SpecifiedPickupDirectory"` to place the email messages in a folder on disk, instead of trying to send them over the network. - -### Pickup directory location - -If you're using the `"SpecifiedPickupDirectory"` option on as the delivery method, this setting allows you to specify what folder the emails should be saved to. - -## Database server registrar settings - -It's unlikely that you will have to change these settings unless you're using a load balanced setup. - -### Wait time between calls - -Sets a value for the amount of time to wait between calls to the database on the background thread. - -### Stale server timeout - -Sets a value for the time span to wait before considering a server stale, after it has last been accessed. - -## Database server messenger - -It's unlikely that you will have change these settings, unless you're using a load balanced setup. These settings are all about how load balancing instructions from the database are processed and pruned. - -### Max processing instruction - -Sets a value for the maximum number of instructions that can be processed at startup; otherwise the server cold-boots (rebuilds its caches). - -### Time to retain instructions - -Sets a value for the time to keep instructions in the database; records older than this number will be pruned. - -### Time between sync operations - -Sets a value for the time to wait between each sync operation. - -### Time between prune operations - -Sets a value for the time to wait between each prune operation. - -### Sanitize TinyMce - -Gets or sets a value indicating whether TinyMCE scripting sanitization should be applied. - -The default value is `false`. - -### Distributed Locking Mechanism - -This is not a setting that commonly needs to be configured. - -Gets or sets a value representing the DistributedLockingMechanism to use. - -Valid values: - -* `"SqlServerDistributedLockingMechanism"` -* `"SqliteDistributedLockingMechanism"` - -### Distributed Read Lock DefaultTimeout - -Gets or sets a value representing the maximum time to wait whilst attempting to obtain a distributed read lock. - -The default value is 60 seconds. - -### Distributed Write Lock DefaultTimeout - -Gets or sets a value representing the maximum time to wait whilst attempting to obtain a distributed write lock. - -The default value is 5 seconds. diff --git a/10/umbraco-cms/reference/configuration/healthchecks.md b/10/umbraco-cms/reference/configuration/healthchecks.md deleted file mode 100644 index 110894119ae..00000000000 --- a/10/umbraco-cms/reference/configuration/healthchecks.md +++ /dev/null @@ -1,96 +0,0 @@ ---- - - -meta.Title: "Umbraco Health Check Settings" -description: "Information on the health check settings section" ---- - -# Health checks - -The health checks section allows you to disable certain health checks, and configure your own custom notification methods, that will automatically run the health checks every so often, and notify you if any health checks fails. - -An example of a HealthChecks settings can look something like this: - -```json -"Umbraco": { - "CMS": { - "HealthChecks": { - "DisabledChecks": [ - { - "Id": "D0F7599E-9B2A-4D9E-9883-81C7EDC5616F" - } - ], - "Notification": { - "Enabled": true, - "FirstRunTime": "* 4 * * *", - "Period": "1.00:00:00", - "NotificationMethods": { - "email": { - "Enabled": true, - "Verbosity": "Detailed", - "FailureOnly": true, - "Settings": { - "RecipientEmail": "alerts@mywebsite.tld" - } - } - } - } - } - } -} -``` - -This config will disable the macro errors check, and enable notifications to run the checks and notify via email if a check fails. The checks will run the first time five minutes after the site is booted, and then once every day. - -The email notification method is built in, if you want to read more about creating you own notification methods, or see a list of the ID of every built in health check, then see [Extending health checks](../../extending/health-check/) - -But let's go through the config one by one - -## Disabled checks - -A list of `DisabledHealthCheckSettings` objects, each of these objects represents a disabled health check. Only the Id key needs to be present and have a value, corresponding to the GUID of the health check to disable. - -There is also a `DisabledOn` key representing the date the health check was disabled and a `DisabledBy` key containing the ID of the user that disabled the health check, however these values are currently not used. - -## Notification - -Settings relating to running the health checks automatically and sending out notifications. - -### Enabled - -Allows you to disable or enable all notifications methods, if set to false, the health checks will not automatically run. - -### First run time - -This will configure when you run the health checks for the first time, if the value is not configured the health checks will run immediately after the site boots for the first time. This value is specified as a string in crontab format, so in this example, the health checks will first run at 4 a.m. - -### Period - -Specifies how often the health checks should run, as a DateTime string, in this example the checks will run every day (every 24 hours). - -### Notification methods - -A dictionary of all the notification methods that should be used. - -The key of the dictionary is the alias of the notification method, and the value is a `HealthChecksNotificationMethodSettings` configuration object, in this case it's the built in `email` notification method. - -Each object allows the following to be configured: - -#### Enabled - -Allows you to enable or disable specific checks. - -#### Verbosity - -Configures how verbose the reporting should be, the available options are: - -* Summary -* Detailed - -#### Failure only - -If set to true, the notification method will only run if a check has failed. - -#### Settings - -Allows you to set custom settings for a given implementation of a notification method, which settings are available depends on the specific implementation. diff --git a/10/umbraco-cms/reference/configuration/hostingsettings.md b/10/umbraco-cms/reference/configuration/hostingsettings.md deleted file mode 100644 index 6614056a4e5..00000000000 --- a/10/umbraco-cms/reference/configuration/hostingsettings.md +++ /dev/null @@ -1,47 +0,0 @@ ---- - -meta.Title: "Umbraco Hosting Settings" -description: "Information on the hosting settings section" ---- - -# Hosting settings - -Hosting settings contains settings regarding the hosting of the site, such as application virtual path, local temporary storage location and debug. - -A full configuration with default values can be seen here: - -```json -"Umbraco": { - "CMS": { - "Hosting": { - "ApplicationVirtualPath": "/", - "LocalTempStorageLocation": "Default", - "Debug": false, - "SiteName" - } - } -} -``` - -## Setting overview - -### Application virtual path - -This setting specified the virtual path of the application, this path must start with a slash. - -### Local temp storage location - -This setting specifies the location of the local temp storage. - -Options: - -* Default -* EnvironmentTemp - -### Debug - -This setting allows you to run Umbraco in debug mode, by setting the value to true. - -### Site name - -Gets or sets a value specifying the name of the site. The [IWebHostEnvironment.ApplicationName](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.ihostenvironment.applicationname?view=dotnet-plat-ext-6.0) is used if not specified diff --git a/10/umbraco-cms/reference/configuration/imagingsettings.md b/10/umbraco-cms/reference/configuration/imagingsettings.md deleted file mode 100644 index b4ee82a7b98..00000000000 --- a/10/umbraco-cms/reference/configuration/imagingsettings.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -meta.Title: Umbraco Imaging Settings -description: Information on the imaging settings section ---- - -# Imaging settings - -The imaging settings section lets you configure the cache and resize settings for processed images on your project (using [ImageSharp.Web](https://docs.sixlabors.com/articles/imagesharp.web/) as default implementation). If you need to configure allowed image file types or auto fill image properties, you want to use [content settings](contentsettings.md) instead. - -All these settings contain default values, so nothing needs to be explicitly configured. A complete settings section for imaging can be seen here with all the default values: - -{% tabs %} -{% tab title="Latest version" %} -```json -"Umbraco": { - "CMS": { - "Imaging": { - "Cache": { - "BrowserMaxAge": "7.00:00:00", - "CacheMaxAge": "365.00:00:00", - "CacheFolderDepth": 8, - "CacheHashLength": 12, - "CacheFolder": "~/umbraco/Data/TEMP/MediaCache" - }, - "Resize": { - "MaxWidth": 5000, - "MaxHeight": 5000 - } - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```json -"Umbraco": { - "CMS": { - "Imaging": { - "Cache": { - "BrowserMaxAge": "7.00:00:00", - "CacheMaxAge": "365.00:00:00", - "CachedNameLength": 8, - "CacheFolder": "~/umbraco/Data/TEMP/MediaCache" - }, - "Resize": { - "MaxWidth": 5000, - "MaxHeight": 5000 - } - } - } -} -``` -{% endtab %} -{% endtabs %} - -## Cache - -Contains configuration for browser and server caching. When changing these cache headers, it is recommended to clear your media cache. This is due to the data being stored in the cache and not updated when the configuration is changed. - -### Browser max age - -Specifies how long a requested processed image may be stored in the browser cache by using this value in the `Cache-Control` response header. The default is 7 days (formatted as a timespan). - -### Cache max age - -Specifies how long a processed image may be used from the server cache before it needs to be re-processed again. The default is one year (365 days, formatted as a timespan). - -### Cache folder depth - -Gets or sets the depth of the nested cache folders structure to store the images. Defaults to 8. - -### Cache hash length - -Gets or sets the length of the filename to use (minus the extension) when storing images in the image cache. Defaults to 12 characters. - -### Cache folder - -Allows you to specify the location of the cached images folder. By default, the cached images are stored in `~/umbraco/Data/TEMP/MediaCache`. The tilde (`~`) resolves to the content root of your project/application. - -## Resize - -Contains configuration for image resizing. - -### Max width/max height - -Specifies the maximum width and height an image can be resized to. If the requested width and height are _both_ above the configured maximums, no resizing will be performed. This adds basic security to prevent resizing big dimensions and using a lot of server CPU/memory to do so. - -The maximum width and height settings are enforced by setting the `ImageSharpMiddlewareOptions.OnParseCommandsAsync` option of ImageSharp to an Umbraco-specific function. If you want to add your own logic without overwriting this behaviour, use the following code: - -```csharp -public class ConfigureImageSharpMiddlewareOptionsComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - => builder.Services.Configure(options => - { - // Capture existing task to not overwrite it - var onParseCommandsAsync = options.OnParseCommandsAsync; - options.OnParseCommandsAsync = async context => - { - // Custom logic before - await onParseCommandsAsync(context); - // Custom logic after - }; - }); -} -``` diff --git a/10/umbraco-cms/reference/configuration/indexingsettings.md b/10/umbraco-cms/reference/configuration/indexingsettings.md deleted file mode 100644 index 2221c80d4e9..00000000000 --- a/10/umbraco-cms/reference/configuration/indexingsettings.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -description: "Information on the indexing section" ---- - -# Indexing Settings - -This section allows you to configure how content is indexed for Examine. - -```json -"Umbraco": { - "CMS": { - "Indexing": { - "ExplicitlyIndexEachNestedProperty": true - } - } -} -``` - -## ExplicitlyIndexEachNestedProperty - -When indexing content, each property contained within certain complex editors are indexed as separate fields by default. These complex editors include: - -- Block List -- Block Grid - -The complex editors are also indexed to their own separate fields, which then contains "the sum" of all properties contained within. - -In some cases this yields a lot of fields in the index, which can lead to errors when performing searches. Changing this setting to `false` can mend that issue. It prevents each contained property from being written to the index in its own field. diff --git a/10/umbraco-cms/reference/configuration/installdefaultdatasettings.md b/10/umbraco-cms/reference/configuration/installdefaultdatasettings.md deleted file mode 100644 index 98741ca458e..00000000000 --- a/10/umbraco-cms/reference/configuration/installdefaultdatasettings.md +++ /dev/null @@ -1,151 +0,0 @@ ---- - - -meta.Title: Umbraco Install Default Data Settings -description: >- - Information on configuration allowing for the modification of default data - installed in new projects ---- - -# Install Default Data Settings - -When Umbraco is installed for the first time, it creates a set of default data. These include a language, some Data Types, and some Media and Member Types. - -In certain setups, you may want to take control over what is installed and opt-out of the creation of certain items. - -When working in a team and using Umbraco Deploy for schema updates, consider your colleague's local project setup. The default installed data may not always be useful. - -For example, if different languages are set up in Umbraco, it's better not to recreate them from the default language (en-US). In other situations, certain Umbraco default Data, Member and Media Types may not be required. - -The following example configuration shows how this default data installation can be customized: - -```json -"Umbraco": { - "CMS": { - "InstallDefaultData": { - "Languages": { - "InstallData": "Values", - "Values": [ - "en-US" - ] - }, - "DataTypes": { - "InstallData": "ExceptValues", - "Values": [ - "0225af17-b302-49cb-9176-b9f35cab9c17" - ] - }, - "MediaTypes": { - "InstallData": "All", - }, - "MemberTypes": { - "InstallData": "None" - } - } - } -} -``` - -Each `InstallData` setting can be one of the following values: - -* `All` - all default data for the type will be installed (this is the default behavior if the configuration is omitted). -* `Values` - only the default data specified will be installed. For languages, the values are the ISO codes for the language. For all other types, the Guid for the type should be listed. -* `ExceptValues` - all default data except those specified will be installed. -* `None` - no default data of the type will be installed. - -{% hint style="warning" %} -Be cautious when changing a Data Type configuration, as there are some dependencies between the different types. Make sure to check the reference information in the `info` tab to ensure they are not referenced somewhere else. -{% endhint %} - -For example, if you check the info tab of the `Label (bigint)` Data Type, you can see that it is referenced by the `Media Types`: - -

Data Type referenced by Media Type

- -## Data Identifiers - -For `DataTypes`, `MediaTypes` and `MemberTypes` the Guid identifiers for the default data items need to be provided in the `Values` collection. - -For `Languages`, the `Values` collection expects the standard language ISO codes to be provided. Given this code is enough to fully specify a language, it's possible to use this collection to install additional default data. - -As an example, the following configuration would omit the default "English (United States)" language and instead install the "English (United Kingdom)" and "Italian" languages. As "English (United Kingdom)" is provided first, it would be created as Umbraco's default language for content creation. - -```json -"Umbraco": { - "CMS": { - "InstallDefaultData": { - "Languages": { - "InstallData": "Values", - "Values": [ - "en-GB", - "it" - ] - } - } - } -} -``` - -## Reference - -The Guid values representing the default Data, Media, and Member Types installed are as follows. - -Data types: - -```none -ApprovedColor = 0225af17-b302-49cb-9176-b9f35cab9c17 -Checkbox = 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 -CheckboxList = fbaf13a8-4036-41f2-93a3-974f678c312a -ContentPicker = FD1E0DA5-5606-4862-B679-5D0CF3A52A59 -DatePicker = 5046194e-4237-453c-a547-15db3a07c4e1 -DatePickerWithTime = e4d66c0f-b935-4200-81f0-025f7256b89a -Dropdown = 0b6a45e7-44ba-430d-9da5-4e46060b9e03 -DropdownMultiple = f38f0ac7-1d27-439c-9f3f-089cd8825a53 -ImageCropper = 1df9f033-e6d4-451f-b8d2-e0cbc50a836f -LabelBigInt = 930861bf-e262-4ead-a704-f99453565708 -LabelDateTime = 0e9794eb-f9b5-4f20-a788-93acd233a7e4 -LabelDecimal = 8f1ef1e1-9de4-40d3-a072-6673f631ca64 -LabelInt = 8e7f995c-bd81-4627-9932-c40e568ec788 -LabelString = f0bc4bfb-b499-40d6-ba86-058885a5178c -LabelTime = a97cec69-9b71-4c30-8b12-ec398860d7e8 -ListViewContent = C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4 -ListViewMedia = 3A0156C4-3B8C-4803-BDC1-6871FAA83FFF -ListViewMembers = AA2C52A0-CE87-4E65-A47C-7DF09358585D -MediaPicker = 135D60E0-64D9-49ED-AB08-893C9BA44AE5 -MediaPicker3 = 4309A3EA-0D78-4329-A06C-C80B036AF19A -MediaPicker3Multiple = 1B661F40-2242-4B44-B9CB-3990EE2B13C0 -MediaPicker3MultipleImages = 0E63D883-B62B-4799-88C3-157F82E83ECC -MediaPicker3SingleImage = AD9F0CF2-BDA2-45D5-9EA1-A63CFC873FD3 -Member = d59be02f-1df9-4228-aa1e-01917d806cda -MemberPicker = 1EA2E01F-EBD8-4CE1-8D71-6B1149E63548 -MultipleMediaPicker = 9DBBCBBB-2327-434A-B355-AF1B84E5010A -Numeric = 2e6d3631-066e-44b8-aec4-96f09099b2b5 -Radiobox = bb5f57c9-ce2b-4bb9-b697-4caca783a805 -RelatedLinks = B4E3535A-1753-47E2-8568-602CF8CFEE6F -RichtextEditor = ca90c950-0aff-4e72-b976-a30b1ac57dad -Tags = b6b73142-b9c1-4bf8-a16d-e1c23320b549 -Textarea = c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3 -Textstring = 0cc0eba1-9960-42c9-bf9b-60e150b429ae -Upload = 84c6b441-31df-4ffe-b67e-67d5bc3ae65a -UploadArticle = bc1e266c-dac4-4164-bf08-8a1ec6a7143d -UploadAudio = 8f430dd6-4e96-447e-9dc0-cb552c8cd1f3 -UploadVectorGraphics = 215cb418-2153-4429-9aef-8c0f0041191b -UploadVideo = 70575fe7-9812-4396-bbe1-c81a76db71b5 -``` - -Media types: - -```none -MediaTypes.Article - a43e3414-9599-4230-a7d3-943a21b20122 -MediaTypes.Audio - a5ddeee0-8fd8-4cee-a658-6f1fcdb00de3 -MediaTypes.File - 4c52d8ab-54e6-40cd-999c-7a5f24903e4d -MediaTypes.Folder - f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d -MediaTypes.Image - cc07b313-0843-4aa8-bbda-871c8da728c8 -MediaTypes.Video - f6c515bb-653c-4bdc-821c-987729ebe327 -"Vector Graphics (SVG)" - c4b1efcf-a9d5-41c4-9621-e9d273b52a9c -``` - -Member types: - -```none -MemberTypes.DefaultAlias - d59be02f-1df9-4228-aa1e-01917d806cda -``` diff --git a/10/umbraco-cms/reference/configuration/keepalivesettings.md b/10/umbraco-cms/reference/configuration/keepalivesettings.md deleted file mode 100644 index 340fde8b46a..00000000000 --- a/10/umbraco-cms/reference/configuration/keepalivesettings.md +++ /dev/null @@ -1,29 +0,0 @@ ---- - - -meta.Title: "Umbraco Keep Alive Settings" -description: "Information on the keep alive settings section" ---- - -# Keep alive settings - -Allows you to configure the keep alive service of Umbraco. A keep alive section fully populated with default values can be seen here: - -```json -"Umbraco": { - "CMS": { - "KeepAlive": { - "DisableKeepAliveTask": false, - "KeepAlivePingUrl": "~/api/keepalive/ping" - } - } -} -``` - -### Disable keep alive task - -Allows you to disable the keep alive http calls. - -### Keep alive ping URL - -If you want to change the URL you need to call to keep the site alive, update this property. The URL should not contain a trailing slash. diff --git a/10/umbraco-cms/reference/configuration/loggingsettings.md b/10/umbraco-cms/reference/configuration/loggingsettings.md deleted file mode 100644 index 5504a471c9c..00000000000 --- a/10/umbraco-cms/reference/configuration/loggingsettings.md +++ /dev/null @@ -1,25 +0,0 @@ ---- - - -meta.Title: "Umbraco Logging Settings" -description: "Information on the logging settings section" ---- - -# Logging settings - -The majority of logging related configuration has been moved to the Serilog configuration see [Serilog settings](serilog.md) for more information. - -This settings section allows you to configure the max log age for the internal audit log scrubbing. The default maximum age for the internal audit log is 24 hours. However, if you want to change this duration, you can use the `"MaxLogAge"` key, like so: - - -```json -"Umbraco": { - "CMS": { - "Logging": { - "MaxLogAge": "2.00:00:00" - } - } -} -``` - -This will increase the maximum age of the entires in the audit log to 48 hours (2 days). diff --git a/10/umbraco-cms/reference/configuration/maximumuploadsizesettings.md b/10/umbraco-cms/reference/configuration/maximumuploadsizesettings.md deleted file mode 100644 index c9ba6316829..00000000000 --- a/10/umbraco-cms/reference/configuration/maximumuploadsizesettings.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -meta.Title: Umbraco Maximum upload size settings -description: Information on how to change the default cap of upload size ---- - -# Maximum Upload Size Settings - -Umbraco does not touch the default maximum allowed content size of the different services, but you can configure this yourself. - -## Using IIS - -To configure the default 28.6MB upload limit using IIS, we have to create a web.config file at the root of the project. It should contain this: - -```xml - - - - - - - - - - - -``` - -`maxAllowedContentLength` is specified in bytes, so this configuration would limit requests, and therefore uploaded files, to 2 megabytes - -{% hint style="info" %} -**Are you hosting your site on Umbraco Cloud?** - -Umbraco Cloud uses IIS for hosting. This means you need to add the setting in a `web.config` file for this to work on your Umbraco Cloud hosted sites. The upload size limit is 500mb on Umbraco Cloud. -{% endhint %} - -## Using Kestrel - -Runtime settings allow you to configure the `MaxRequestLength` and `MaxQueryStringLength` for kestrel. If you want to upload files larger than 50MB, then you have to configure these settings. If nothing is configured requests and query strings can only be the default size and smaller. - -An example of a configuration could look something like this: - -```json -"Umbraco": { - "CMS": { - "Runtime": { - "MaxQueryStringLength": 90, - "MaxRequestLength": 2000 - } - } -} -``` - -`MaxRequestLength` is specified in kilobytes. This configuration will limit requests, and therefore uploaded files, to 2 megabytes, and a maximum query string length of 90 characters. - -## [Using Nginx (external)](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) - -## [Using apache (external)](https://httpd.apache.org/docs/2.2/mod/core.html#limitrequestbody) diff --git a/10/umbraco-cms/reference/configuration/modelsbuildersettings.md b/10/umbraco-cms/reference/configuration/modelsbuildersettings.md deleted file mode 100644 index fd868a324de..00000000000 --- a/10/umbraco-cms/reference/configuration/modelsbuildersettings.md +++ /dev/null @@ -1,66 +0,0 @@ ---- - - -meta.Title: "Umbraco Models Builder Settings" -description: "Information on the models builder settings section" ---- - -# Models builder settings - -This section allows you to configure the Umbraco models builder, a complete section with default values can be seen here: - -```json -"Umbraco": { - "CMS": { - "ModelsBuilder": { - "ModelsMode": "InMemoryAuto", - "ModelsNamespace": "Umbraco.Cms.Web.Common.PublishedModels", - "FlagOutOfDateModels": false, - "ModelsDirectory": "~/umbraco/models", - "AcceptUnsafeModelsDirectory": false, - "DebugLevel": 0 - } - } -} -``` - -Let's go through them one by one - -## Models mode - -Specifies how the models builder will generate models and when to generate them. The options are: - -* `Nothing` - The modelsbuilder will not generate any models, this means that all views will use IPublishedContent, instead of strongly typed models. -* `InMemoryAuto` - Models will automatically be generated each time a content type change occurs, and will then be compiled, and loaded into memory dynamically. This means that the models are only available in views, however they will be available instantly. -* `SourceCodeManual` - Models will be generated as `.cs` files whenever a user clicks the "Generate models" button on the models builder dashboard - however, the models will not be compiled and loaded into memory dynamically. This means that models are available to edit within the project. The project needs to be recompiled and restarted for the new models, or model changes, to take effect. -* `SourceCodeAuto` - This mode behaves the same as `SourceCodeManual` with one difference, the generation of models happens automatically every time a content type change occurs. - -## Models namespace - -This setting allows you to customize the namespace of the generated models, for instance you might want to change this to something that aligns better with your project structure, such as `MySite.ContentModels`. - -## Flag out of date models - -This setting allows you to specify if a model should be flagged as out of date if its content type, or a datatype the content type depends on, are changed. When a model is flagged as out of date you will be able to see that you need to regenerated models in modelsbuilder dashboard. - -This setting is only really relevant if you use the `SourceCodeManual` models mode, since otherwise the models will be automatically regenerated, and will therefore never be out of date. - -If you set this setting to true while using an `Auto` mode, it will automatically be interpreted as false. - -## Models directory - -Allows you to specify a custom directory for your generated models. By default this settings has to be a virtual directory, that is, it must start with `~/`, if needed `AcceptUnsafeModelsDirectory` can be set to true, to allow the path to be outside the website root, be aware though that this is a potential security risk. - -{% hint style="info" %} -If you want to generate models outside the web project you can change the ModelsDirectory path. Suppose you have a data project called My.Website.Data the ModelsDirectory path should be: - -`~/../My.Website.Data/Models/` -{% endhint %} - -## Accept unsafe models directory - -By setting this to true, you specify that the models directory is allowed to be outside the websites root. This is not allowed by default since it can be a potential security risk. - -## Debug level - -This setting specifies the logging level for the models builder. By default this is set to 0, which means minimal logging. Anything higher that 0 means increased logging. Be aware that this setting should only be set to something higher than 0 for development use, not on live sites. diff --git a/10/umbraco-cms/reference/configuration/nucachesettings.md b/10/umbraco-cms/reference/configuration/nucachesettings.md deleted file mode 100644 index 5066aac31a0..00000000000 --- a/10/umbraco-cms/reference/configuration/nucachesettings.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -description: "Information on the NuCache settings section" ---- - -# NuCache Settings - -The NuCache settings allow you to configure different aspects of how cached content is stored and retrieved. Below are the details of the available settings and how they can be configured to optimize performance and compatibility with your project needs. - -## BTreeBlockSize - -```json -"Umbraco": { - "CMS": { - "NuCache": { - "BTreeBlockSize": 4096 - } - } -} -``` - -{% hint style="info" %} -The block size must be a power of two. It should be at least 512 and at most 65536 (64K). -{% endhint %} - -## NuCacheSerializerType - -The `NuCacheSerializerType` setting allows developers to specify the serialization format for NuCache content. This setting is particularly relevant for projects migrating from older versions of Umbraco that relied on JSON formats. - -To use JSON serialization instead of the default MessagePack: - -### Using 'Program.cs' - -```csharp -builder.Services.Configure(options => -{ - options.NuCacheSerializerType = NuCacheSerializerType.JSON; -}); -``` - -### Using 'appsettings.json' - -```csharp -{ - "Umbraco": { - "CMS": { - "NuCache": { - "NuCacheSerializerType": "JSON" - } - } - } -} -``` - -## Additional Settings - -You can configure NuCache to work in memory only without reading/writing to the NuCache database files. Startup duration may increase for larger sites during a "warm boot" but smaller sites should see minimal impact. The settings have not yet been exposed via the new configuration setup, instead you must configure with a composer. - -```csharp -public class DisableNuCacheDatabaseComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - var settings = new Umbraco.Cms.Infrastructure.PublishedCache.PublishedSnapshotServiceOptions - { - IgnoreLocalDb = true - }; - builder.Services.AddSingleton(settings); - } -} -``` diff --git a/10/umbraco-cms/reference/configuration/packagemigrationsettings.md b/10/umbraco-cms/reference/configuration/packagemigrationsettings.md deleted file mode 100644 index 9480b78e7ad..00000000000 --- a/10/umbraco-cms/reference/configuration/packagemigrationsettings.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -versionFrom: 9.0.1 - -meta.Title: "Umbraco Package Migration Settings" -description: "Information on the package migration settings section" ---- - -# Package Migration - -This settings section provides control over how package migrations are executed in different environments (local, development, live etc.) - -Package migrations are defined by package developers allowing them to add functionality to their package that enhances the Umbraco CMS. There can be various types of migrations applied, including creating custom database tables and installing Umbraco schema and content. - -They run on start-up, thus ensuring that the functionality of the package has the necessary infrastructure, schema, and content in place when it is used. - -Migration steps that are explicitly created by the package developer to make database schema changes will always run in all environments. - -Depending on your workflow, for those steps that install Umbraco data - whether schema such as document types, content, or media - you may want them run in all environments, or you may prefer to only do this in certain ones. - -The default behavior for Umbraco CMS is for all package migrations to run in all environments. - -If using Umbraco Cloud, the default is to run package migrations fully _only in local environments_. By doing this, for schema, `.uda` files will be generated in the `/umbraco/Deploy/Revision` folder, which when pushed to a Cloud environment will be used to install the schema and content there. For content and media, the "queue for transfer" operation can be used. With this behavior, we avoid any issues caused by both a package migration and a deployment operation attempting to create schema and content. - -If different behavior is required, or if using Umbraco Deploy On-Premises, the following settings can be applied: - -```json -{ - "$schema": "https://json.schemastore.org/appsettings.json", - "Umbraco": { - "CMS": { - "PackageMigration": { - "RunSchemaAndContentMigrations": true, - "AllowComponentOverrideOfRunSchemaAndContentMigrations": true - } - } - } -} -``` - -## RunSchemaAndContentMigrations - -If set to `true`, the default behavior described above for Umbraco CMS on-premises and Umbraco Cloud will be applied. By setting to `false`, the installation of Umbraco schema and content from a package migration will be skipped. If missing the default value is `true`. - -## AllowComponentOverrideOfRunSchemaAndContentMigrations - -If this is set to the default value of `true`, Umbraco Cloud (or other deployment tools) can override the configured value of `RunSchemaAndContentMigrations` as is appropriate for their operation. By setting to `false` such tools should respect this setting, not make any overrides and use the configured value. diff --git a/10/umbraco-cms/reference/configuration/pluginssettings.md b/10/umbraco-cms/reference/configuration/pluginssettings.md deleted file mode 100644 index 8b475114bf8..00000000000 --- a/10/umbraco-cms/reference/configuration/pluginssettings.md +++ /dev/null @@ -1,29 +0,0 @@ ---- - - -meta.Title: "Umbraco Plugins Settings" -description: "Information on the plugins settings section" ---- - -# Plugins settings - -The plugins settings allow you to configure how Umbraco handles plugins, currently you can only configure browsable file extensions, which allows you to customize what file types plugins are allowed to use for the front end. The default configuration looks like this: - -```json -"Umbraco": { - "CMS": { - "Plugins": { - "BrowsableFileExtensions": [ - ".html", - ".css", - ".js", - ".jpg", ".jpeg", ".gif", ".png", ".svg", - ".eot", ".ttf", ".woff", - ".xml", ".json", ".config", - ".lic"] - } - } -} -``` - -As you can see above, by default, markup, styles, scripts, images, fonts, configurations, and license type are included. If you were to, for example, remove the ".html" entry, then plugins would no longer be allowed to use HTML files. \ No newline at end of file diff --git a/10/umbraco-cms/reference/configuration/requesthandlersettings.md b/10/umbraco-cms/reference/configuration/requesthandlersettings.md deleted file mode 100644 index 3d993214973..00000000000 --- a/10/umbraco-cms/reference/configuration/requesthandlersettings.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -meta.Title: Umbraco Request Handler Settings -description: Information on the request handler settings section ---- - -# Request handler settings - -The options in the request handler let us do some quite useful things, like deciding whether or not to use trailing slashes and setting URL replacement for special characters. - -Let's have a further look at each option below. - -Here is a snippet containing all the default values of the `RequestHandler` section. - -```js -"Umbraco": { - "CMS": { - "RequestHandler": { - "AddTrailingSlash": true, - "ConvertUrlsToAscii": "try", - "EnableDefaultCharReplacements": true, - "CharCollection": [ - { - "Char": " ", - "Replacement": "-" - }, - { - "Char": "\\", - "Replacement": "" - }, - { - "Char": "'", - "Replacement": "" - }, - { - "Char": "%", - "Replacement": "" - }, - { - "Char": ".", - "Replacement": "" - }, - { - "Char": ";", - "Replacement": "" - }, - { - "Char": "/", - "Replacement": "" - }, - { - "Char": "\\\\", - "Replacement": "" - }, - { - "Char": ":", - "Replacement": "" - }, - { - "Char": "#", - "Replacement": "" - }, - { - "Char": "+", - "Replacement": "plus" - }, - { - "Char": "*", - "Replacement": "star" - }, - { - "Char": "&", - "Replacement": "" - }, - { - "Char": "?", - "Replacement": "" - }, - { - "Char": "æ", - "Replacement": "ae" - }, - { - "Char": "ä", - "Replacement": "ae" - }, - { - "Char": "ø", - "Replacement": "oe" - }, - { - "Char": "ö", - "Replacement": "oe" - }, - { - "Char": "å", - "Replacement": "aa" - }, - { - "Char": "ü", - "Replacement": "ue" - }, - { - "Char": "ß", - "Replacement": "ss" - }, - { - "Char": "|", - "Replacement": "-" - }, - { - "Char": "<", - "Replacement": "" - }, - { - "Char": ">", - "Replacement": "" - } - ] - } - } -} -``` - -## Add trailing slash - -This will add a trailing slash to the url when **``** is set to "true". If you don't want to have a trailing slash, set the value to **false**. - -### Convert urls to ascii - -This setting tells Umbraco to convert all urls to ASCII, if set to false the urls will remain UTF-8. - -This setting can be set to **try** This will make the engine try to convert the name to an ASCII implementation. If it fails, it will fallback to the name. Reason is that some languages don't have ASCII implementations, therefore the urls would end up being empty. - -### Enable default character replacements - -This setting tells Umbraco to use the default character replacements. If you don't want the default character replacements, set this to false. - -### Char collection - -This settings contains a lot of obejcts with a **`"Char"`** and **`"Replacement`** key, each of these object holds a character that should be replaced, and what it should be replaced with. - -So, if: - -```json -{ - "Char": "ñ", - "Replacement": "n" -} -``` - -is added to the list, the **ñ** will be shown as a **n** in the url. diff --git a/10/umbraco-cms/reference/configuration/richtexteditorsettings.md b/10/umbraco-cms/reference/configuration/richtexteditorsettings.md deleted file mode 100644 index 06d530d8d8c..00000000000 --- a/10/umbraco-cms/reference/configuration/richtexteditorsettings.md +++ /dev/null @@ -1,108 +0,0 @@ ---- - - -meta.Title: "Umbraco Rich Text Editor Settings" -description: "Information on the Rich text editor settings section" ---- - -# Rich text editor settings - -This settings section allows you to configure the behaviour of the rich text editor, everything from plugins to commands. Everything has a default value, so it's not required to configure any of this yourself. - -A config with all the values can be seen underneath. Since there is a lot of defaults configured, some of these have been omited for the sake of readability, anywhere something has been omitted it's shown with `{...}`. - - -```json -"Umbraco": { - "CMS": { - "RichTextEditor": { - "Plugins": ["paste", "anchor", "charmap", "table", "lists", "advlist", "hr", "autolink", "directionality", "tabfocus", "searchreplace"], - "ValidElements": "+a[id|style|rel|data-id|data-udi|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-s[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],-sub[style|class],-sup[style|class],-blockquote[dir|style|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*],figure,figcaption,cite,video[*],audio[*],picture[*],source[*],canvas[*]", - "InvalidElements": "font", - "Commands": [ - { - "Alias": "ace", - "Name": "Source code editor", - "Mode": "Insert" - }, - { - "Alias": "removeformat", - "Name": "Remove format", - "Mode": "Selection" - }, - { - "Alias": "paste", - "Name": "Paste", - "Mode": "All" - }, - {...} - ], - "CustomConfig": { - "entity_encoding": "raw" - } - } - } -} -``` - -## Plugins - -Allows you to specify what plugins should be enabled for the rich text editor as a comma separated list of the plugin names. - -## Valid elements - -Allows you to specify the valid HTML elements for the rich text editor as well as the allowed properties, for instance, in the config above the `a` element is allowed, and it's allowed to have `onclick`, `href`, and many more attributes. - -## Invalid elements - -Specifies invalid HTML elements for the rich text editor - -## Commands - -Allows you to specify what commands should be available, as a list of object. These commands are the little buttons you find at the top of the editor, such as bold, italic, and so on. - -When specifying these, every object should contain: - -* Alias - The alias of the command -* Name - A friendly name descriping the command -* Mode - The mode the command runs on - * Insert - The command will insert something - * Selection - The command operate on the text, or elements, selected - * All - The command operates on everything - -## Custom config - -Allows you to specify custom key value pairs for the rich text editor. - -### Examples -Remove default ```

``` tag. -```json - "Umbraco": { - "CMS": { - "RichTextEditor": { - "CustomConfig": { - "forced_root_block": "" - } - } - } - } -``` - -Add custom styles to the **Formats** dropdown list in the Richtext Editor. - -{% hint style="info" %} -Use a text editor to find and replace `\"` with `"`. This will allow you to edit the JSON file in an easier-to-read format. Don't forget to add the `\` back in when you are ready to paste the code back into your `appsettings.json` file. -{% endhint %} - -```json - "Umbraco": { - "CMS": { - "RichTextEditor": { - "CustomConfig": { - "style_formats": "[{\"title\":\"Headers\",\"items\":[ {\"title\":\"Heading 1\",\"block\":\"h1\"}, {\"title\":\"Heading 2\",\"block\":\"h2\"}, {\"title\":\"Heading 3\",\"block\":\"h3\"}, {\"title\":\"Heading 4\",\"block\":\"h4\"}, {\"title\":\"Heading 5\",\"block\":\"h5\"} ]}]" - } - } - } - } -``` - diff --git a/10/umbraco-cms/reference/configuration/runtimeminificationsettings.md b/10/umbraco-cms/reference/configuration/runtimeminificationsettings.md deleted file mode 100644 index b16ff9a931a..00000000000 --- a/10/umbraco-cms/reference/configuration/runtimeminificationsettings.md +++ /dev/null @@ -1,65 +0,0 @@ ---- - - -meta.Title: "Umbraco Runtime Minification Settings" -description: "Information on the runtime minification settings section" ---- - -# Runtime minification settings - -This section allows you to configure the runtime minifications (defaults shown), used by ['Smidge - A lightweight runtime CSS/Javascript minification,combination, compression & management library for ASP.NET'](https://github.com/shazwazza/smidge) - -```json -"Umbraco": { - "CMS": { - "RuntimeMinification": { - "UseInMemoryCache": false, - "CacheBuster": "Version" - } - } -} -``` -## Use 'in memory' cache - -This setting determines whether Smidge should save it's cached output in memory, or in a file on disk. If set to false, then the folder will be created at the wwwroot of your Umbraco site in a folder called 'Smidge'/ - -{% hint style="info" %} -It is not possible to disable in memory caching when `Timestamp` is chosen as `CacheBuster` method. -{% endhint %} - -## Cache buster - -Specifies mechanism for cache invalidation. - -The options are: - -* Version - Caches will be busted when your assembly version changes, when the upstream Umbraco version changes and when the version string specified in Configuration changes. -* AppDomain - Caches will be busted when the app restarts. -* Timestamp - Caches will be busted based on a timestamp of the bundled files. - -## Manually changing the Cache buster version - -If you use a CacheBuster setting of "Version" you can add an additional configuration option, also called 'Version' , which allows you to set a value that you can incremement manually, or via a build server to make sure the version number changes for Smidge and busts the cache. - -```json -"Umbraco": { - "CMS": { - "RuntimeMinification": { - "UseInMemoryCache": true, - "CacheBuster": "Version", - "Version": "1234" - } - } -} -``` -The actual 'Version' number will not be visible in the url of the assets, this is because it is combined, along with the Umbraco Version from configuration and the your project assembly dll, and then once combined a 'hash' is generated to obscure these details. - -in the HTML link thus: `````` (when [`Umbraco:CMS:Hosting:Debug:false`](hostingsettings.md)) - -So if you increased the Version in the configuration by 1 to 1235, all you would see is a different hash! - -{% hint style="info" %} -For production environments, it's recommended to set Cache Buster to 'Version' (you don't actually need to supply a version number, but if you do, you can control when the cache breaks, eg if a package has installed new assets) or to 'AppDomain'. -{% endhint %} - -Another configuration option (of Smidge) is the `"dataFolder`" setting, this setting specifies what folder Smidge will use for its temporary data, it should not be necessary to change this either, it will only be used if UseInMemoryCache is set to false. diff --git a/10/umbraco-cms/reference/configuration/runtimesettings.md b/10/umbraco-cms/reference/configuration/runtimesettings.md deleted file mode 100644 index f006054b38c..00000000000 --- a/10/umbraco-cms/reference/configuration/runtimesettings.md +++ /dev/null @@ -1,30 +0,0 @@ ---- - - -meta.Title: Umbraco Runtime Settings -description: Information on the runtime settings section ---- - -# Runtime settings - -Runtime settings allows you to configure the `MaxRequestLength` and `MaxQueryStringLength` for your application. Neither of these settings needs to be configured. If nothing is configured reqests and query string can be any size. - -An example of a configuration could look something like: - -```json -"Umbraco": { - "CMS": { - "Runtime": { - "MaxQueryStringLength": 90, - "MaxRequestLength": 2048, - "Mode": "BackofficeDevelopment" - } - } -} -``` - -`MaxRequestLength` is specified in kilobytes, limiting requests, and therefore uploaded files, to 2 megabytes. Additionally, it sets a maximum query string length of 90 characters. - -`Mode` can have three values: `BackofficeDevelopment` (default), `Development`, and `Production`. - -For more information, see the [Runtime modes](../../fundamentals/setup/server-setup/runtime-modes.md) article. diff --git a/10/umbraco-cms/reference/configuration/securitysettings.md b/10/umbraco-cms/reference/configuration/securitysettings.md deleted file mode 100644 index 9f792160e5f..00000000000 --- a/10/umbraco-cms/reference/configuration/securitysettings.md +++ /dev/null @@ -1,126 +0,0 @@ ---- - - -meta.Title: "Umbraco Security Settings" -description: "Information on the security settings section" ---- - -# Security Settings - -The options in the security section allows you to configure all things security, whether to keep users logged in, password rules and more. - -A full configuration with all default values can be seen here: - -```json -"Umbraco": { - "CMS": { - "Security": { - "KeepUserLoggedIn": false, - "HideDisabledUsersInBackOffice": false, - "AllowPasswordReset": true, - "AuthCookieName": "UMB_UCONTEXT", - "AuthCookieDomain": "", - "UsernameIsEmail": true, - "UserPassword": { - "RequiredLength": 10, - "RequireNonLetterOrDigit": false, - "RequireDigit": false, - "RequireLowercase": false, - "RequireUppercase": false, - "HashAlgorithmType": "PBKDF2.ASPNETCORE.V3", - "MaxFailedAccessAttemptsBeforeLockout": 5 - }, - "MemberPassword": { - "RequiredLength": 10, - "RequireNonLetterOrDigit": false, - "RequireDigit": false, - "RequireLowercase": false, - "RequireUppercase": false, - "HashAlgorithmType": "PBKDF2.ASPNETCORE.V3", - "MaxFailedAccessAttemptsBeforeLockout": 5 - }, - "UserDefaultLockoutTimeInMinutes": 43200, - "MemberDefaultLockoutTimeInMinutes": 43200 - } - } -} -``` - -## Root level settings - -At the root level of security you can configure the following - -### Keep user logged in - -When set to false a user will be logged out after a specific amount of time has passed with no activity. You can specify this time span in the [global settings](globalsettings.md) with the `TimeOut` key. - -### Hide disabled users in backoffice - -When this is set to "true" it's not possible to see disabled users. This means it's not possible to re-enable their access to the backoffice again. It also means you can't create an identical username if the user was disabled by a mistake. - -### Allow password reset - -This feature allows users to reset their passwords if they have forgotten them. By default, this is enabled. It can be disabled at both the UI and API level by setting this value to "false". - -### Auth cookie name - -The authentication cookie which is set in the browser when a backoffice user logs in, and defaults to `UMB_UCONTEXT`. - -### Auth cookie domain - -The authentication cookie which is set in the browser when a backoffice user logs in is automatically set to the current domain. - -### Username is email - -This setting specifies whether the username and email address are separate fields in the backoffice editor. When set to "false", you can specify an email address and username, only the username can be used to log on. When set to "true" (the default value) the username is hidden and always the same as the email address. - -## User password settings - -This section lets you define the password rules for users. - -### Required length - -Specifies the minimum length a user password is allowed to be. - -### Require non letter or digit - -Requires a users password to contain at least one character which is not a letter or a digit if enabled. - -### Require digit - -Requires a users password to contain at least one digit if enabled. - -### Require lowercase - -Requires a users password to contain at least on lowercase letter if enabled. - -### Max failed access attempts before lockout - -Specifies the max amount of failed password attempts is allowed before the user is locked out of the site. - -### Hash algorithm type - -Allows you to specify what hashing algorithm should be used to store the users password. - -Options are: - -* `"PBKDF2.ASPNETCORE.V3"` -* `"PBKDF2.ASPNETCORE.V2"` -* `"HMACSHA256"` -* `"HMACSHA1"` - -## Member password settings - -This section allows you to define the password rules for members. This section is identical to the one for users. - -## User Default Lockout Time In Minutes - -Use this setting to configure how long time a User is locked out of the Umbraco backoffice when a lockout occurs. The setting accepts an integer which defines the lockout in minutes. - -The default lockout time for users is 30 days (43200 minutes). - -## Member Default Lockout Time In Minutes - -Use this setting to configure how long time a Member is locked out of the Umbraco website when a lockout occurs. The setting accepts an integer which defines the lockout in minutes. - -The default lockout time for users is 30 days (43200 minutes). diff --git a/10/umbraco-cms/reference/configuration/serilog.md b/10/umbraco-cms/reference/configuration/serilog.md deleted file mode 100644 index ebc3097be49..00000000000 --- a/10/umbraco-cms/reference/configuration/serilog.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -description: "Information on the serilog settings section" ---- - -# Serilog settings - -Umbraco uses Serilog as its logging library, this means that the configuration of logging is offloaded to Serilog instead of the CMS. This means that logging specific configuration is not in the `Umbraco.Cms` section, but instead the Serilog section. - -We will go through some of the more common logging configurations here, but for more information see the [Serilog settings GitHub project](https://github.com/serilog/serilog-settings-configuration). - -## Default configuration - -When you create a new Umbraco project the following Serilog section will be included by default: - -```json -"Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "System": "Warning" - } - } -} -``` - -## Specifying minimum log level - -As you can see above, the CMS comes with a default Serilog config that defines the minimum log level with the `"MinimumLevel"` key. - -You can specify the overall minimum log level with the `"Default"` key. This will apply to all namespaces, however it's also possible to override this log level for specific names spaces with the `"Override"` key. In the example above, any logging coming from the `Microsoft` and `System` namespaces will only log warnings and up, however the `Microsoft.Hosting.Lifetime` namespace will log information and up. - -The possible values, from most verbose to least, is: - -* Verbose -* Debug -* Information -* Warning -* Error -* Fatal - -For information on what each of these levels means see [the serilog wiki](https://github.com/serilog/serilog/wiki/Configuration-Basics#minimum-level). - - -## Changing the log level for specific namespaces - -This can be done by updating the appsettings.json configuration file to specify namespaces in which you want to change the log level for. - -```json - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "System": "Warning", - "Examine.Lucene.Providers.LuceneIndex": "Debug", - "Examine.BaseIndexProvider": "Debug", - "MyNamespace": "Verbose" - } - } - } -``` - -## Logging to a different output - -Serilog has the ability to log to a number of different mechanisms, from console to files, even to Slack or email. This is all configured using what Serilog calls sinks. - -An example of this can be seen in the default `appsettings.Development.json`, where Serilog is configured to log to the console using the Async wrapper sink: - -```json - "Serilog": { - "MinimumLevel": { - "Default": "Information" - }, - "WriteTo": [ - { - "Name": "Async", - "Args": { - "configure": [ - { - "Name": "Console" - } - ] - } - } - ] - } -``` - -Here you can see that we use the `"WriteTo"` key to specify a list of sinks the logger should write to. In this case we use the `"Async"` sink configured to write to the console, this means that we'll log to the console asynchronously. - -Now there's too many sinks to cover here, for a full list of all available sinks see [Provided sinks](https://github.com/serilog/serilog/wiki/Provided-Sinks#list-of-available-sinks). Each of these entries will have their own documentation on how to set up the logging with the particular sink. - -## Changing the Umbraco 'sink' -By default, Umbraco uses a special Serilog 'sink' that is optimized for performance. To change parameters for only this sink, but not the default. For E.g higher log lever for this compared to other sinks you can do it in the following way: - -```json - "Serilog": { - "MinimumLevel": { - "Default": "Information" - }, - "WriteTo": [ - { - "Name": "UmbracoFile", - "Args": { - "RestrictedToMinimumLevel": "Warning", - "FileSizeLimitBytes": 1073741824, - "RollingInterval" : "Day", - "FlushToDiskInterval": null, - "RollOnFileSizeLimit": false, - "RetainedFileCountLimit": 31 - } - } - ] - } -``` - -## Adding a custom log property to all log items - -You may wish to add a log property to all log messages. A good example could be a log property for the `environment` to determine if the log message came from `development` or `production`. - -This is useful when you could be writing logs from all environments or multiple customer projects into a single logging source, such as Elasticsearch. This would allow you to search and filter for a specific project and its environment to see the log messages. You can also reference your hosting server's environment variables in the property values. - -In the `appsettings.json` configuration file you can add the following lines - -```json - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "System": "Warning" - } - }, - "Properties": { - "Customer": "Super Customer", - "Environment": "Production" - } - } -``` diff --git a/10/umbraco-cms/reference/configuration/tourssettings.md b/10/umbraco-cms/reference/configuration/tourssettings.md deleted file mode 100644 index 251d206f65c..00000000000 --- a/10/umbraco-cms/reference/configuration/tourssettings.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -description: "Information on the tours settings section" ---- - -# Tours settings - -The tours section is a section that only contains one value `"EnableTours"` which allows you to enable or disable tours, by default tours are enabled. If you wish to disable tours set the `"EnableTours"` to false, like so: - -```json -"Umbraco": { - "CMS": { - "Tours": { - "EnableTours": false - } - } -} -``` diff --git a/10/umbraco-cms/reference/configuration/typefindersettings.md b/10/umbraco-cms/reference/configuration/typefindersettings.md deleted file mode 100644 index eabd04d7936..00000000000 --- a/10/umbraco-cms/reference/configuration/typefindersettings.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -meta.Title: Umbraco Type Finder Settings -description: Information on the type finder settings section ---- - -# Type finder settings - -The type finder settings allows you to specify assemblies that accept load exceptions when they are type scanned. For multiple assemblies separate them with a comma (`,`). To accept load exceptions for all assemblies use an asterisk (`*`), like so: - -Furthermore it is possible to add additional assemblies to the exclusion filter. Thereby these assemblies will be ignored by Umbraco. This can be useful depending on nuget packages that are not Umbraco packages. - -```json -"Umbraco": { - "CMS": { - "TypeFinder": { - "AssembliesAcceptingLoadExceptions": "*", - "AdditionalAssemblyExclusionEntries": [] - } - } -} -``` diff --git a/10/umbraco-cms/reference/configuration/unattendedsettings.md b/10/umbraco-cms/reference/configuration/unattendedsettings.md deleted file mode 100644 index 0a7106f207e..00000000000 --- a/10/umbraco-cms/reference/configuration/unattendedsettings.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -description: "Information on the unattended settings section" ---- - -# Unattended - -These settings let you configure the unattended install & upgrade settings. This is a feature that allows Umbraco to install without using the User Interface (UI). If you don't intended to use this feature, you don't need to configure this. - -It's important to know that the install feature will only work if there is a connection string configured pointing to an empty database. A configuration for unattended install & upgrade can look something like: - -```json -{ - "$schema": "https://json.schemastore.org/appsettings.json", - - "ConnectionStrings": { - "umbracoDbDSN": "Server=.;Database=DocsSite;Integrated Security=true" - }, - "Umbraco": { - "CMS": { - "Unattended": { - "InstallUnattended": true, - "PackageMigrationsUnattended": true, - "UpgradeUnattended": true, - "UnattendedUserName": "A.N. Other", - "UnattendedUserEmail": "AN@Other.com", - "UnattendedUserPassword": "APasswordMeetingRequirements" - } - } - } -} -``` - -This will automatically install Umbraco to the `DocsSite` database on the local SQL server, and will also automatically upgrade whenever there is an upgrade to install. - -It is generally not recommended to keep user credentials in config files, therefore we recommend using environment variables to configure these settings. - -Let's go through the settings one by one - -## Install unattended - -Umbraco will only automatically install if this is set to true, and if there is a connection string pointing to an empty database. - -## Upgrade unattended - -If this is set to true, Umbraco will automatically run the upgrade migrations once the site has been upgraded. - -## Unattended user name - -This setting is used to specify the user name of the default admin user. - -## Unattended email - -This setting is used to specify the email address of the default admin user. - -## Unattended user pass - -This setting is used to specify the password of the default admin user. - -### Package migrations unattended - -Gets or sets a value indicating whether unattended package migrations are enabled. - -This is true by default. diff --git a/10/umbraco-cms/reference/configuration/webroutingsettings.md b/10/umbraco-cms/reference/configuration/webroutingsettings.md deleted file mode 100644 index 8e8bddb2fff..00000000000 --- a/10/umbraco-cms/reference/configuration/webroutingsettings.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -description: Information on the web routing settings section ---- - -# Web routing - -This section allows you to configure routing for your solution, all of these settings have either default values, or do not need to be configured. However, you might want to tweak these settings in some scenarios, for instance, if you're running in a load-balanced setup. - -An example of a web routing config with default values, and a placeholder for the application URL can be seen here: - -```json -"Umbraco": { - "CMS": { - "WebRouting": { - "TryMatchingEndpointsForAllPages": false, - "TrySkipIisCustomErrors": false, - "InternalRedirectPreservesTemplate": false, - "DisableAlternativeTemplates": false, - "ValidateAlternativeTemplates": false, - "DisableFindContentByIdPath": false, - "DisableRedirectUrlTracking": false, - "UrlProviderMode": "Auto", - "UmbracoApplicationUrl": "http://www.mysite.com/" - } - } -} -``` - -{% hint style="warning" %} -**Are you on Umbraco Cloud?** - -It is not possible to change the `UmbracoApplicationUrl setting` because the value is overwritten to the default Umbraco URL: `https://[project-alias].[region].umbraco.io/`on Umbraco Cloud. -{% endhint %} - -## Try matching endpoints for all pages - -When set to `true` Umbraco will check if any routed endpoints match a front-end request. This happens before the Umbraco dynamic router tries to map the request to a Umbraco content item. This setting should not be necessary as long as the Umbraco catch-all route is registered last. - -## Try skip IIS custom errors - -Defines the value of Response.TrySkipIisCustomErrors when an error (404, 400, 500...) is encountered. In order to prevent IIS from displaying its own 404 or 500 pages, set this to `true` to have your own page displayed. - -## Internal redirect preserves template - -When true, an internal redirect does not reset the alternative template, if any. - -## Disable alternative templates - -When true, the entire alternative templates feature of Umbraco is disabled. - -**validateAlternativeTemplates** will not load the template from the database. If `false` the template might not exists in the database. Otherwise the template need to exist in the database. - -## Validate alternative templates - -If set to true alternative templates will be validated - -## Disable find content by ID path - -When true, content can't be found by their ID meaning that urls such as /1234 do _not_ find content with ID 1234. - -## Disable redirect URL tracking - -When you move and rename pages in Umbraco, 301 permanent redirects are automatically created, set this to true if you do not want this behavior. - -## URL provider mode - -Will set the URL provider mode, options are: - -* `Default`: Indicates that the URL provider should do what it has been configured to do. -* `Relative`: Indicates that the URL provider should produce relative URLs exclusively. -* `Absolute`: Indicates that the URL provider should produce absolute URLs exclusively. -* `Auto`: Indicates that the URL provider should determine automatically whether to return relative or absolute URLs. - -## Umbraco application URL - -Defines the Umbraco application URL that the server should reach itself. By default, Umbraco will guess that URL from the first request made to the server. Use this setting if the guess is not correct (because you are behind a load-balancer, for example). Format is: `http://www.mysite.com/`, ensure to contain the scheme (http/https) and complete hostname. - -{% hint style="info" %} -Previously before v9, it was required to specify **backoffice** path as this was customizable (`/umbraco` by default). However, from v9+ this is no longer possible, so it's sufficient to use the URL that contains the scheme (http/https) and complete hostname. -{% endhint %} diff --git a/10/umbraco-cms/reference/debugging.md b/10/umbraco-cms/reference/debugging.md deleted file mode 100644 index 5aa5d4e911d..00000000000 --- a/10/umbraco-cms/reference/debugging.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -meta.Title: Debugging with SourceLink -description: >- - Information on SourceLink and how to use it to debug the Umbraco CMS source - code ---- - -# Debugging with SourceLink - -Microsoft and Visual Studio have introduced a new debugging technology called 'SourceLink' that enables source code debugging of certain .NET assemblies from NuGet. This feature has been enabled to allow developers to step into the native Umbraco CMS source code. - -## Enabling SourceLink in Visual Studio 2017 & 2019 - -1. Navigate to **Tools** -> **Options** -> **Debugging** -> **General**. -2. In the **General** window, uncheck `Enable Just My Code` option and check `Enable Source Link support` option. -3. Click **OK** to save the changes. - - ![Visual Studio 2019 Debug Settings for SourceLink](images/VS19-enable-sourcelink.png) - -## What is SourceLink? - -To read about SourceLink, you can take a look at the following websites: - -* [Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/standard/library-guidance/sourcelink) -* [Scott Hanselman blog post on Sourcelink](https://www.hanselman.com/blog/ExploringNETCoresSourceLinkSteppingIntoTheSourceCodeOfNuGetPackagesYouDontOwn.aspx) -* [SourceLink on GitHub](https://github.com/dotnet/sourcelink) - -## Working with SourceLink - -* Create a new `.NET 5.0` Framework blank/empty website. -* Install the latest Umbraco CMS 9.0+ Nuget Packages from Nuget.org -* Create an IComposer or similar code in your new site/SLN that you want to F11/Step Into. [Example Code Snippet to try with SourceLink](debugging.md#example-code-snippet-to-try-with-sourcelink) -* Prompt will appear and the original source code file is fetched directly from GitHub. ![Visual Studio 2019 SourceLink dialog](images/VS19-sourcelink-prompt.png) -* How far can you `F11`, also known as `Step Into`, and go down the rabbit hole of the Umbraco CMS source code? - -### Example Code Snippet to try with SourceLink - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace WebApplication23 -{ - public class MyComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Components().Append(); - } - } - - public class MyComponent : IComponent - { - private IContentService _contentService; - - public MyComponent(IContentService contentService) - { - _contentService = contentService; - } - - public void Initialize() - { - // Add break point & F11 into me - var root = _contentService.GetRootContent(); - - foreach (var item in root) - { - // Add break point & F11 into me - var udi = item.GetUdi(); - var foo = 5; - } - } - - public void Terminate() - { - } - } -} -``` diff --git a/10/umbraco-cms/reference/distributed-locks.md b/10/umbraco-cms/reference/distributed-locks.md deleted file mode 100644 index 5ba2e898cbf..00000000000 --- a/10/umbraco-cms/reference/distributed-locks.md +++ /dev/null @@ -1,31 +0,0 @@ -# Distributed Locks - -During save operations, Umbraco will generally take a database lock to avoid concurrency issues. - -Access to this feature is via the `IScope` interface, for example: - -```csharp - using (var scope = _scopeProvider.CreateScope()) -{ - scope.WriteLock(Constants.Locks.Domains); - - // Carry out save operation. - - scope.Complete(); -} -``` - -Each lockable entity is represented by an integer Id, stored along with the state of the lock in the `umbracoLock` database table. - -Packages or custom solutions working with custom data via the `IScope` interface can introduce their own records to this table. However it's important to not clash with either core identifiers or those introduced by other packages. - -A reference is maintained here of known identifiers: - -| Id | Name | Used By | -|--------------|----------------------|------------------| -| -1000 | MainDom | Umbraco CMS | -| -331 to -340 | Various | Umbraco CMS | -| -800 | DeployTransferQueue | Umbraco Deploy | - - - diff --git a/10/umbraco-cms/reference/dive-into-the-code.md b/10/umbraco-cms/reference/dive-into-the-code.md deleted file mode 100644 index fb8202e9144..00000000000 --- a/10/umbraco-cms/reference/dive-into-the-code.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -description: >- - Learn more about what you can find in this section, which is referred to as - the "Developers Reference". ---- - -# Dive into the code - -The developers' Reference section primarily consists of API references of the different core Umbraco APIs. In many cases, the references come with code snippets with examples. - -The section also includes documentation about the different configuration options, security, advanced templating, and searching. - -
ConfigurationMost configuration in Umbraco CMS is handled via the appSettings.json file.configurationsetup-image.png
TemplatingWork with MVC views and Razor templates to build the frontend for your Umbraco CMS website.templatingdesign.png
Querying & ModelsEverything you need to extend your templates with filters, models, and more advanced queries.queryingdatap-image.png
Routing and ControllersDive into working with routers and controllers for customizing your Umbraco CMS even further.routingcontrollers-image.png
SecurityFind everything you need related to keeping your Umbraco CMS website secure.securitysecurity-imag.png
SearchingLearn about Examine and Lucene which are tools utilized in Umbraco for the search functionality.searchingsearching-image.png
NotificationsLearn how to use notifications to hook into the workflow processes for the backoffice.notificationsnotifications-image.png
CachingLearn how to implement caching features in the Umbraco CMS application.cachecaching-image.png
API DocumentationDive into the deep end and start exploring the different sections of the Umbraco CMS API.api-documentation.mdapi-docs-image.png
- -## Also in this section - -{% content-ref url="using-ioc.md" %} -[using-ioc.md](using-ioc.md) -{% endcontent-ref %} - -{% content-ref url="response-caching.md" %} -[response-caching.md](response-caching.md) -{% endcontent-ref %} - -{% content-ref url="plugins/" %} -[plugins](plugins/) -{% endcontent-ref %} - -{% content-ref url="common-pitfalls.md" %} -[common-pitfalls.md](common-pitfalls.md) -{% endcontent-ref %} - -{% content-ref url="debugging.md" %} -[debugging.md](debugging.md) -{% endcontent-ref %} - -{% content-ref url="language-variation.md" %} -[language-variation.md](language-variation.md) -{% endcontent-ref %} - -{% content-ref url="mapping.md" %} -[mapping.md](mapping.md) -{% endcontent-ref %} diff --git a/10/umbraco-cms/reference/images/VS19-enable-sourcelink.png b/10/umbraco-cms/reference/images/VS19-enable-sourcelink.png deleted file mode 100644 index 9fb55917f99..00000000000 Binary files a/10/umbraco-cms/reference/images/VS19-enable-sourcelink.png and /dev/null differ diff --git a/10/umbraco-cms/reference/images/VS19-sourcelink-prompt.png b/10/umbraco-cms/reference/images/VS19-sourcelink-prompt.png deleted file mode 100644 index 724dfacb8fe..00000000000 Binary files a/10/umbraco-cms/reference/images/VS19-sourcelink-prompt.png and /dev/null differ diff --git a/10/umbraco-cms/reference/language-variation.md b/10/umbraco-cms/reference/language-variation.md deleted file mode 100644 index 0b05df9063f..00000000000 --- a/10/umbraco-cms/reference/language-variation.md +++ /dev/null @@ -1,109 +0,0 @@ -# Language Variation - -Language Variation allows you to have different variations of content based on a language culture. In the documentation there are other useful articles about the feature: - -* [Getting started with Language Variants](../fundamentals/backoffice/variants.md) -* [Rendering variant values](../fundamentals/design/rendering-content.md) - -[`IPublishedContent`](querying/ipublishedcontent/) contains all language variations of a node, and when rendering it out it will then use the Culture you are currently on. This can then be overridden on an individual property level if you want, like this: - -```csharp -@Model.Value("pageTitle", "fr", fallback: Fallback.ToLanguage) -``` - -Here we would attempt to render the `pageTitle` property in the French variant. We want to fallback to the current culture language if it can't find it in French. - -The challenge arises when trying to display all values of an IPublishedContent model in a specific culture from a "current culture"-less context, like a [`SurfaceController`](routing/surface-controllers/). - -If you do something like this: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Website.Controllers; -using Umbraco.Extensions; - -namespace TestStuff -{ - public class TestController : SurfaceController - { - - public TestController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - public IActionResult Index() - { - var culturedRootNode = CurrentPage.Root(); - TempData.Add("CulturedRootNode", culturedRootNode); - - return View(); - } - } -} -``` - -You will get the root node in the default culture. However you can set a new `VariationContext` like this: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Website.Controllers; -using Umbraco.Extensions; - -namespace TestStuff -{ - public class TestController : SurfaceController - { - private readonly IVariationContextAccessor _variationContextAccessor; - - public TestController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider, - IVariationContextAccessor variationContextAccessor) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - _variationContextAccessor = variationContextAccessor; - } - - public IActionResult Index() - { - const string culture = "af"; // Afrikaans - - // This is how the culture is set for the context we are in - _variationContextAccessor.VariationContext = new VariationContext(culture); - - var culturedRootNode = CurrentPage.Root(); - TempData.Add("CulturedRootNode", culturedRootNode); - - return View(); - } - } -} -``` - -So we access the `IVariationContextAccessor.VariationContext` and set it to a new one with our own specified culture (remember `using Umbraco.Core.Models.PublishedContent;` at the top to get access to it). - -The elements you get afterwards will be in the culture you have specified. diff --git a/10/umbraco-cms/reference/management/README.md b/10/umbraco-cms/reference/management/README.md deleted file mode 100644 index f053d9010fa..00000000000 --- a/10/umbraco-cms/reference/management/README.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -description: >- - Details of CRUD operations within Umbraco and how to interact with the data - persisted in the database ---- - -# Management - -The intended audience for these reference pages are .NET developers. It is assumed the reader already has knowledge of the basics of Umbraco and knows .NET & C#. - -{% hint style="info" %} -Since the release of Umbraco 10, we will no longer be updating the articles in this section. - -You can find up-to-date code references for all Models in our [API Documentation](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Models.html). -{% endhint %} - -## [Models](models/) - -Here you will find references for the models in the public API. The models include Content, ContentType, DataTypeDefinition, DictionaryItem, Language, Media, MediaType, Relation, RelationType, Task, TaskType, and Template classes. - -## [Services](services/) - -Here you will find references for the services which are available for performing Create, Read, Update and Delete (CRUD) operations for the models mentioned above. diff --git a/10/umbraco-cms/reference/management/models/README.md b/10/umbraco-cms/reference/management/models/README.md deleted file mode 100644 index ea313c814f1..00000000000 --- a/10/umbraco-cms/reference/management/models/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Persistence Models reference - diff --git a/10/umbraco-cms/reference/management/models/content.md b/10/umbraco-cms/reference/management/models/content.md deleted file mode 100644 index d8ce887d670..00000000000 --- a/10/umbraco-cms/reference/management/models/content.md +++ /dev/null @@ -1,336 +0,0 @@ ---- -description: "The Content class represents a single item in the content tree, its values are fetched directly from the database, not from the cache." ---- - -# Content - -The `Content` class represents a single item in the content tree, its values are fetched directly from the database, not from the cache. **Notice** the Content class should strictly be used for CRUD operations, not complex queries, as it is not flexible nor fast enough for this. - -All content is versioned, so on each individual change, a new version is stored. Past versions can only be retrieved from the `Content` api, not from the cache. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -``` - -## Constructors - -### new Content(string name, IContent parent, IContentType contentType, string culture = null) - -Constructor for creating a new Content object where the necessary parameters are the name of the Content, the parent of the Content as an `IContent` object and the ContentType as an `IContentType` object for the Content being created. In addition, there is an optional parameter for the culture. - -### new Content(string name, IContent parent, IContentType contentType, int userId, string culture = null) - -Constructor for creating a new Content object where the necessary parameters are the name of the Content, the parent of the Content as an `IContent` object, the ContentType as an `IContentType` object for the Content being created and the id of the user as a `int`. In addition, there is an optional parameter for the culture. - -### new Content(string name, IContent parent, IContentType contentType, PropertyCollection properties, string culture = null) - -Constructor for creating a new Content object where the necessary parameters are the name of the Content, the parent of the Content as an `IContent` object, the ContentType as an `IContentType` object and a `PropertyCollection` for the Content being created. In addition, there is an optional parameter for the culture. - -### new Content(string name, int parentId, IContentType contentType, string culture = null) - -Constructor for creating a new Content object where the necessary parameters are the name of the Content, the id of the parent as `int` and the ContentType as an `IContentType` object for the Content being created. In addition, there is an optional parameter for the culture. - -### new Content(string name, int parentId, IContentType contentType, int userId, string culture = null) - -Constructor for creating a new Content object where the necessary parameters are the name of the Content, the parent id of the Content as an `int` object, the ContentType as an `IContentType` object for the Content being created and the id of the user as a `int`. In addition, there is an optional parameter for the culture. - -### new Content(string name, int parentId, IContentType contentType, PropertyCollection properties, string culture = null) - -Constructor for creating a new Content object where the necessary parameters are the name of the Content, the id of the parent as `int`, the ContentType as an `IContentType` object and a `PropertyCollection` for the Content being created.In addition, there is an optional parameter for the culture. - -## Properties - -### .CreateDate - -Gets or Sets a `DateTime` object, indicating then the given Content was created. - -```csharp -// Given a `ContentService` object get Content by its Id and return CreateDate -var content = contentService.GetById(1234); -return content.CreateDate; -``` - -### .CreatorId - -Gets or Sets the Id of the `User` who created the Content. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Id of the Creator -var content = contentService.GetById(1234); -return content.CreatorId; -``` - -### .ContentType - -Returns a `ISimpleContentType` object representing the DocumentType used by the given `Content`. - -```csharp -// Given a `ContentService` object get Content by its Id and return ContentType -var content = contentService.GetById(1234); -return content.ContentType; -``` - -### .ContentTypeId - -Returns the id as an `int` of the `ContentType` object representing the DocumentType used by the given `Content`. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Id of the ContentType -var content = contentService.GetById(1234); -return content.ContentTypeId; -``` - -### .Id - -Returns the unique `Content` Id as a `Int`, this ID is based on a Database identity field, and is therefore not safe to reference in code which are moved between different instances, use Key instead. - -### .Key - -Returns the `Guid` assigned to the Content during creation. This value is unique, and should never change, even if the content is moved between instances. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Key -var content = contentService.GetById(1234); -return content.Key; -``` - -### .PublishedCultures - -Gets Languages of the Content as a `IEnumerable`. - -### .Level - -Gets or Sets the given `Content` level in the site hierarchy as an `Int`. Content placed at the root of the site, will return 1, content right underneath will return 2, and so on. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Level -var content = contentService.GetById(1234); -return content.Level; -``` - -### .Name - -Gets or Sets the name of the content as a `String`. - -```csharp -// Given a `ContentService` object get Content by its Id and return its Name -var content = contentService.GetById(1234); -return content.Name; -``` - -### .ParentId - -Gets or Sets the parent `Content` Id as an `Int`. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Id of the Parent Content -var content = contentService.GetById(1234); -return content.ParentId; -``` - -### .Path - -Gets or Sets the path of the content as a `String`. This string contains a comma separated list of the ancestor Ids including the current contents own id at the end of the string. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Path -var content = contentService.GetById(1234); -return content.Path; -``` - -### .Properties - -Gets or Sets the `IPropertyCollection` object, which is a collection of `IProperty` objects. Each property corresponds to a `PropertyType`, which is defined on the `ContentType`. - -```csharp -// Given a `ContentService` object get Content by its Id and loop through all Properties -var content = contentService.GetById(1234); -foreach (var property in content.Properties) -{ - string alias = property.Alias; - object value = property.GetValue(); - -} -``` - -### .Published - -Returns a `Bool` indicating whether the given `Content` is published and available on the website or not. **Notice:** the published flag does not check the current in-memory cache, so this flag is not a guarantee that the Content is/is not available in the cache and the frontend of the website. - -```csharp -// Given a `ContentService` object get Content by its Id and return Published -var content = contentService.GetById(1234); -return content.Published; -``` - -### .PublishDate - -If set, returns `DateTime?` indicating when the `Content` should be published and made available on the website and cache. - -```csharp -// Given a `ContentService` object get Content by its Id and set the release date to 4 days from now -var content = contentService.GetById(1234); -return content.PublishDate -``` - -### .SortOrder - -Returns the given `Content` index, compared to sibling content. - -```csharp -// Given a `ContentService` object get Content by its Id and return its SortOrder -var content = contentService.GetById(1234); -return content.SortOrder; -``` - -### .PublishedState - -Returns a `IPublishedState` enum with the status of the Content being either Unpublished, Published, Publishing, Unpublishing. - -```csharp -// Given a `ContentService` object get Content by its Id and return its Status -var content = contentService.GetById(1234); -return content.PublishedState; -``` - -### .TemplateId - -Gets or sets the template id used to render the content. - -```csharp -// Given a `ContentService` object get Content by its Id and return its Template -var content = contentService.GetById(1234); -return content.TemplateId; -``` - -### .Trashed - -Returns a `Bool` indicating whether the given `Content` is currently in the recycle bin. - -```csharp -// Given a `ContentService` object get Content by its Id and return Trashed -var content = contentService.GetById(1234); -return content.Trashed; -``` - -### .UpdateDate - -Gets or Sets a `DateTime` object, indicating when the given Content was last updated. - -```csharp -// Given a `ContentService` object get Content by its Id and return UpdateDate -var content = contentService.GetById(1234); -return content.UpdateDate; -``` - -### .VersionId - -Returns the current Version Id as a `int`, for each change made to a content item, its values are stored under a new Version. This version is identified by a `int`. - -```csharp -// Given a `ContentService` object get Content by its Id and return its Version -var content = contentService.GetById(1234); -return content.VersionId; -``` - -### .WriterId - -Gets or Sets the Id of the `User` who made the latest edit on the Content. - -```csharp -// Given a `ContentService` object get Content by its Id and return the Id of the Writer -var content = contentService.GetById(1234); -return content.WriterId; -``` - -## Methods - -### .GetCreatorProfile(IUserService userService) - -Gets the `IProfile` object for the Creator of this Content, which contains the Id and Name of the User who created this Content item. - -```csharp -// Given a `ContentService` object get Content by its Id and get the `IProfile` of the Creator -var content = contentService.GetById(1234); -var profile = content.GetCreatorProfile(userService); -var id = profile.Id; -string name = profile.Name; -``` - -### .GetValue(string propertyTypeAlias) - -Gets the value of a Property as an `Object`. - -```csharp -// Given a `ContentService` object get Content by its Id and get a value by alias -var content = contentService.GetById(1234); -object value = content.GetValue("bodyText"); -string text = value as string; -``` - -### .GetValue< TPassType >(string propertyTypeAlias) - -Gets the value of a Property as the defined type 'TPassType'. - -```csharp -// Given a `ContentService` object get Content by its Id and get a value by alias while specifying the return type -var content = contentService.GetById(1234); -string value = content.GetValue("bodyText"); -``` - -### .GetWriterProfile(IUserService userService) - -Gets the `IProfile` object for the Writer of this Content, which contains the Id and Name of the User who last updated this Content item. - -```csharp -// Given a `ContentService` object get Content by its Id and get the `IProfile` of the Writer -var content = contentService.GetById(1234); -var profile = content.GetWriterProfile(userService); -var id = profile.Id; -string name = profile.Name; -``` - -### .HasProperty(string propertyTypeAlias) - -Returns a `Bool` indicating whether the Content object has a property with the supplied alias. - -```csharp -// Given a `ContentService` object get Content by its Id and check if certain properties exist -var content = contentService.GetById(1234); -bool tagsExists = content.HasProperty("myTagProperty"); -bool bodyTextExists = content.HasProperty("bodyText"); -``` - -### .SetValue(string propertyTypeAlias, object value) - -Sets the value of a property by its alias. - -```csharp -// Given a `ContentService` object get Content by its Id, set a few values -// and saves the Content through the `ContentService` -var content = contentService.GetById(1234); -content.SetValue("bodyText", "This text will be added to by RTE field"); -content.SetValue("date", DateTime.Now); -contentService.Save(content); -``` - -### .ToXml(IEntityXmlSerializer serializer) - -Returns an `XElement` containing the Content data, based off the latest changes. Is used when the published content is sent to the in-memory xml cache. - -```csharp -// Given a `ContentService` object get Content by its Id and returns the xml -var content = contentService.GetById(1234); -XElement xml = content.ToXml(serializer); -return xml; -``` diff --git a/10/umbraco-cms/reference/management/models/contenttype.md b/10/umbraco-cms/reference/management/models/contenttype.md deleted file mode 100644 index 4e86532fc6c..00000000000 --- a/10/umbraco-cms/reference/management/models/contenttype.md +++ /dev/null @@ -1,354 +0,0 @@ ---- -description: "A ContentType corresponds to the Document Type found in the backoffice." ---- - -# ContentType - -A ContentType corresponds to the Document Type found in the backoffice. The ContentType is a model / data definition for your content nodes. Every content node on an Umbraco web site always maps to a backing Document Type. - -A Document Type is composed by Properties, which are grouped by Tabs (or PropertyGroups in the API). It can also inherit properties and tabs from other Document Types. - -It is possible to link one or more Templates to a Document Type. This determines how your model/data is rendered to the user. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -``` - -## Constructors - -### ContentType(IShortStringHelper shortStringHelper, IContentType parent, string alias) - -Constructor for creating a new `ContentType` object. The necessary parameters are a short string helper `IShortStringHelper`, the parent `ContentType` as an `IContentType` and the alias of the new `ContentType` as `string`. - -### new ContentType(IShortStringHelper shortStringHelper, int parentId) - -Constructor for creating a new `ContentType` object where the necessary parameters are a short string helper `IShortStringHelper` and the Id of the parent `ContentType` as an `Int`. - -## Properties - -### .Alias - -Gets or Sets the Alias as a `String` of the ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return Alias -var contentType = contentTypeService.Get(1234); -return contentType.Alias; -``` - -### .AllowedAsRoot - -Gets or Sets a `Bool` indicating whether this ContentType is allowed at the root. If one or more ContentTypes are set to 'AllowedAsRoot' only they are shown in the create dialog at the root level in the backoffice. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return AllowedAsRoot -var contentType = contentTypeService.Get(1234); -return contentType.AllowedAsRoot; -``` - -### .AllowedContentTypes - -Gets or Sets an `Enumerable` list of `ContentTypeSort` objects of the ContentTypes allowed under the current ContentType. - -The `ContentTypeSort` is an object with a lazy Id, int SortOrder and string Alias used to sort the MediaTypes within the list of AllowedContentTypes. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return AllowedContentTypes -var contentType = contentTypeService.Get(1234); -return contentType.AllowedContentTypes; -``` - -### .AllowedTemplates - -Gets or Sets an `Enumerable` list of `ITemplates` which are allowed for the current ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return AllowedTemplates -var contentType = contentTypeService.Get(1234); -return contentType.AllowedTemplates; -``` - -### .ContentTypeComposition - -Gets a list of `ContentTypes` as `IContentTypeComposition` objects that make up a composition of PropertyGroups and PropertyTypes for the current ContentType. - -The ContentTypeComposition provides a mixin-type functionality in that you can compose a ContentType of one or more other ContentTypes in a complex structure. But please be aware that the backoffice does not fully support these complex structures yet. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return ContentTypeComposition -var contentType = contentTypeService.Get(1234); -return contentType.ContentTypeComposition; -``` - -### .CompositionPropertyGroups - -Gets a list of all 'PropertyGroup\` objects from the composition including PropertyGroups from the current ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return CompositionPropertyGroups -var contentType = contentTypeService.Get(1234); -return contentType.CompositionPropertyGroups; -``` - -### .CompositionPropertyTypes - -Gets a list of all `PropertyType` objects from the composition including PropertyTypes from the current ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return CompositionPropertyTypes -var contentType = contentTypeService.Get(1234); -return contentType.CompositionPropertyTypes; -``` - -### .CreateDate - -Gets or Sets a `DateTime` object, indicating then the given ContentType was created. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return CreateDate -var contentType = contentTypeService.Get(1234); -return contentType.CreateDate; -``` - -### .CreatorId - -Gets or Sets the Id of the `User` who created the ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Id of the Creator -var contentType = contentTypeService.Get(1234); -return contentType.CreatorId; -``` - -### .Description - -Gets or Sets the Description as a `String` for the ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Description -var contentType = contentTypeService.Get(1234); -return contentType.Description; -``` - -### .DefaultTemplate - -Gets the default Template set as an `ITemplate` object for this ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the DefaultTemplate -var contentType = contentTypeService.Get(1234); -return contentType.DefaultTemplate; -``` - -### .Icon - -Gets or Sets the Icon as a `String` for the ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Icon -var contentType = contentTypeService.Get(1234); -return contentType.Icon; -``` - -### .Id - -Gets the unique `ContentType` Id as an `Int`. The ID, derived from a database identity field, isn't safe for code references as they are moved across instances. Therefore it's recommended to use `Key` instead. - -### .Key - -Gets the `Guid` assigned to the ContentType during creation. This value is unique, and should never change, even if the content is moved between instances. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Key -var contentType = contentTypeService.Get(1234); -return contentType.Key; -``` - -### .Level - -Gets or Sets the given `ContentType` level in the site hierarchy as an `Int`. ContentTypes placed at the root of the tree, will return 1, content right underneath will return 2, and so on. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Level -var contentType = contentTypeService.Get(1234); -return contentType.Level; -``` - -### .Name - -Gets or Sets the name of the ContentType as a `String`. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return its Name -var contentType = contentTypeService.Get(1234); -return contentType.Name; -``` - -### .ParentId - -Gets or Sets the parent `ContentType` Id as an `Int`. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Id of the Parent ContentType -var contentType = contentTypeService.Get(1234); -return contentType.ParentId; -``` - -### .Path - -Gets or Sets the path of the ContentType as a `String`. This string contains a comma separated list of the ancestors Ids including the current ContentTypes own id at the end of the string. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Path -var contentType = contentTypeService.Get(1234); -return contentType.Path; -``` - -### .PropertyGroups - -Gets or Sets a `PropertyGroupCollection` containing a list of PropertyGroups for the current ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return PropertyGroups -var contentType = contentTypeService.Get(1234); -return contentType.PropertyGroups; -``` - -### .PropertyTypes - -Gets an `Enumerable` list of PropertyTypes aggregated for all groups within the current ContentType, as well as PropertyTypes not within a group. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return PropertyTypes -var contentType = contentTypeService.Get(1234); -return contentType.PropertyTypes; -``` - -### .SortOrder - -Gets the given `ContentType` index, compared to sibling content. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return its SortOrder -var contentType = contentTypeService.Get(1234); -return contentType.SortOrder; -``` - -### .Thumbnail - -Gets or Sets the Thumbnail as a `String` for the ContentType. - -```csharp -// Given a `ContentTypeService` object get ContentType by its Id and return the Thumbnail -var contentType = contentTypeService.Get(1234); -return contentType.Thumbnail; -``` - -## Methods - -### .AddContentType(IContentTypeComposition contentType) - -Adds a new `ContentType` to the list of composite ContentTypes. - -```csharp -// Given a `ContentTypeService` object get a few ContentTypes by their alias -// and add the 'Meta' and 'SEO' ContentTypes to the composition of the 'Textpage' ContentType. -var metaContentType = contentTypeService.Get("meta"); -var seoContentType = contentTypeService.Get("seo"); -var textpageContentType = contentTypeService.Get("textPage"); -textpageContentType.AddContentType(metaContentType); -textpageContentType.AddContentType(seoContentType); -contentTypeService.Save(textpageContentType); -``` - -### .CompositionAliases() - -Returns an `Enumerable` list of ContentType aliases as `String` from the current composition. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias and loop through CompositionAliases -var contentType = contentTypeService.Get("textPage"); -var aliases = contentType.CompositionAliases(); -``` - -### .CompositionIds() - -Returns an `Enumerable` list of ContentType Ids as `Int` from the current composition. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias and loop through CompositionIds -var contentType = contentTypeService.Get("textPage"); -var ids = contentType.CompositionIds(); -``` - -### .ContentTypeCompositionExists(string alias) - -Checks if a `ContentType` with the supplied alias exists in the list of composite ContentTypes. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias -// and check if a given ContentType exists in the composition of the 'Text Page' ContentType. -var contentType = contentTypeService.Get("textPage"); -bool result = contentType.ContentTypeCompositionExists("meta"); -``` - -### .SetDefaultTemplate(ITemplate template) - -Sets the default `Template` for the current ContentType. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias -// and change the default template with another one from the list of allowed templates. -var contentType = contentTypeService.Get("textPage"); -ITemplate template = contentType.AllowedTemplates.First(x => x.Alias == "anotherTemplate"); -contentType.SetDefaultTemplate(template); -contentTypeService.Save(contentType); -``` - -### .RemoveContentType(string alias) - -Removes a `ContentType` with the supplied alias from the list of composite ContentTypes. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias and -// remove the 'Meta' ContentType from its composition. -var contentType = contentTypeService.Get("textPage"); -bool success = contentType.RemoveContentType("meta"); -if(success) - contentTypeService.Save(contentType); -``` - -### .RemovePropertyType(string propertyTypeAlias) - -Removes a `PropertyType` from the current `ContentType`. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias -// and remove a PropertyType from the list of PropertyTypes. -var contentType = contentTypeService.Get("textPage"); -contentType.RemovePropertyType("author"); -contentTypeService.Save(contentType); -``` - -### .RemoveTemplate(ITemplate template) - -Removes a `Template` from the list of allowed templates. - -```csharp -// Given a `ContentTypeService` object get a ContentType by its alias -// and remove one of the templates from the list of allowed templates. -var contentType = contentTypeService.Get("textPage"); -ITemplate template = contentType.AllowedTemplates.First(x => x.Alias == "RemoveThisTemplate"); -contentType.RemoveTemplate(template); -contentTypeService.Save(contentType); -``` diff --git a/10/umbraco-cms/reference/management/models/datatype.md b/10/umbraco-cms/reference/management/models/datatype.md deleted file mode 100644 index 28b860d0599..00000000000 --- a/10/umbraco-cms/reference/management/models/datatype.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -description: "A DataType is what you see in the backoffice in the Settings / DataTypes tree. The listed nodes are definitions of the DataTypes that are available to use on your PropertyTypes." ---- - -# DataType - -A DataType is what you see in the backoffice in the Settings / DataTypes tree. The listed nodes are definitions of the DataTypes that are available to use on your PropertyTypes. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statement: - -```csharp -using Umbraco.Cms.Core.Models; -``` - -## Constructors - -### new DataType(IDataEditor editor, IConfigurationEditorJsonSerializer serializer, int parentId = -1) - -Constructor for creating a new `DataType` object where the necessary parameters are a `IDataEditor` and a `IConfigurationEditorJsonSerializer`. Optionally, the parentId can be added, if not provided the default value is -1, which means it will be created at root level. - -## Properties - -### .CreateDate - -Gets or Sets a `DateTime` object, indicating then the given DataType was created. - -### .CreatorId - -Gets or Sets the Id of the `User` who created the DataType. - -### .DatabaseType - -Gets or Sets the DatabaseType as a `ValueStorageType` enum for which the DataType's value is saved as. - -### .Id - -Returns the unique `DataType` ID as an `Int`. The ID, derived from a database identity field, isn't safe for code references as they are moved across instances. Therefore it's recommended to use `Key` instead. - -### .Key - -Returns the `Guid` assigned to the DataType during creation. This value is unique, and should never change, even if the DataType is moved between instances. - -### .Level - -Gets or Sets the given `DataType` level in the site hierarchy as an `Int`. DataType placed at the root of the site, will return 1, DataType right underneath will return 2, and so on. - -### .Name - -Gets or Sets the name of the `DataType` as a `String`. - -### .ParentId - -Gets or Sets the parent `DataType` Id as an `Int`. - -### .Path - -Gets or Sets the path of the `DataType` as a `String`. This string contains a comma separated list of the ancestor Ids including the current contents own id at the end of the string. - -### .SortOrder - -Returns the given `DataType` index, compared to sibling DataType. - -### .Trashed - -Returns a `Bool` indicating whether the given `DataType` is currently in the recycle bin. diff --git a/10/umbraco-cms/reference/management/models/dictionaryitem.md b/10/umbraco-cms/reference/management/models/dictionaryitem.md deleted file mode 100644 index 4879d210dd5..00000000000 --- a/10/umbraco-cms/reference/management/models/dictionaryitem.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -description: "Represents a Dictionary Item. A Dictionary Item is what you see in the Translation / Dictionary tree." ---- - -# DictionaryItem - -Represents a Dictionary Item. A Dictionary Item is what you see in the Translation / Dictionary tree. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statement: - -```csharp -using Umbraco.Cms.Core.Models; -``` - -## Constructors - -### new DictionaryItem(string itemKey) - -Constructor for creating a new `DictionaryItem` object where the necessary parameter is the key of the `DictionaryItem` as a `string`. - -### new DictionaryItem(Guid? parentId, string itemKey) - -Constructor for creating a new `DictionaryItem` object where the necessary parameters are the parentKey as `Guid` and the key of the `DictionaryItem` as a `string`. Use this one if you want to create a `DictionaryItem` underneath another one. - -## Properties - -### .ItemKey - -Gets or sets the Key for the Dictionary Item. - -```csharp -// Create a DictionaryItem and return the key -var dictionaryItem = new DictionaryItem("your_key"); -return dictionaryItem.ItemKey; -``` - -### .ParentId - -Gets or Sets a `Guid?` of the Dictionary Item ParentId. - -```csharp -// Create a DictionaryItem and return the parentId -DictionaryItem dictionaryItem = new DictionaryItem("your_key"); -Guid? parentId = dictionaryItem.ParentId; -return parentId; -``` - -### .Translations - -Gets or sets a `IEnumerable` of translations for the Dictionary Item. - -```csharp -// Create a DictionaryItem and return the translations -var dictionaryItem = new DictionaryItem("your_key"); -return dictionaryItem.Translations; -``` diff --git a/10/umbraco-cms/reference/management/models/language.md b/10/umbraco-cms/reference/management/models/language.md deleted file mode 100644 index d2e7847765b..00000000000 --- a/10/umbraco-cms/reference/management/models/language.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -description: "Represents a Language. Installed languages can be found in the settings section." ---- - -# Language - -Represents a Language. Installed languages can be found in the settings section. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statement: - -```csharp -using Umbraco.Cms.Core.Models; -``` - -## Constructors - -### new Language(GlobalSettings globalSettings, string isoCode) - -Constructor for creating a new `Language` object where the necessary parameter are the global settings as `GlobalSettings` and the isoCode as a `string`. - -{% hint style="info" %} -To create a new Language the global setting parameter is necessary. You can find more info about how to use configuration in code in the [Config article](../../configuration/#reading-configuration-in-code). -{% endhint %} - -## Properties - -### .CultureInfo - -Gets the CultureInfo object for the language. - -```csharp -var language = new Language(globalSettings, "en-US"); -CultureInfo cultureInfo = language.CultureInfo; -return cultureInfo; -``` - -### .CultureName - -Gets or sets the culture name of the language. - -```csharp -var language = new Language(globalSettings, "en-US"); -string cultureName = language.CultureName; -return cultureName; -``` - -### .FallbackLanguageId - -Gets or sets the identifier of a fallback language. The fallback language can be used in multi-lingual scenarios, to help define fallback strategies when a value does not exist for a requested language. - -```csharp -var language = new Language(globalSettings, "en-US"); -int? fallbackLanguageId = language.FallbackLanguageId; -return fallbackLanguageId; -``` - -### .IsDefault - -Gets or sets a value indicating whether the language is the default language. - -```csharp -var language = new Language(globalSettings, "en-US"); -bool isDefault = language.IsDefault; -return isDefault; -``` - -### .IsMandatory - -Gets or sets a value indicating whether the language is mandatory. When a language is mandatory, a multi-lingual document cannot be published without that language being published, and unpublishing that language unpublishes the entire document. - -```csharp -var language = new Language(globalSettings, "en-US"); -bool isMandatory = language.IsMandatory; -return isMandatory; -``` - -### .IsoCode - -Gets or sets the ISO code of the language. - -```csharp -var language = new Language(globalSettings, "en-US"); -return language.IsoCode; -``` diff --git a/10/umbraco-cms/reference/management/models/media.md b/10/umbraco-cms/reference/management/models/media.md deleted file mode 100644 index e5d980645a0..00000000000 --- a/10/umbraco-cms/reference/management/models/media.md +++ /dev/null @@ -1,268 +0,0 @@ ---- -description: "The Media class represents a single item in the media tree." ---- - -# Media - -The `Media` class represents a single item in the media tree, its values are fetched directly from the database, not from the cache. **Notice** the Media class should strictly be used for CRUD operations. Media is already stored in cache, so for querying Media you'd want to use the `IUmbracoContext.IPublishedMediaCache` to get the media. Then one would use [LINQ to query and filter the collection](../../querying/ipublishedcontent/collections.md). - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -``` - -## Constructors - -### new Media(string name, IMedia parent, IMediaType mediaType) - -Constructor for creating a new Media object where the necessary parameters are the name of the Media, the parent of the Media as an `IMedia` object and the MediaType as an `IMediaType` object for the Media being created. - -### new Media(string name, IMedia parent, IMediaType mediaType, IPropertyCollection properties) - -Constructor for creating a new Media object where the necessary parameters are the name of the Media, the parent of the Media as an `IMedia` object, the MediaType as an `IMediaType` object and a `IPropertyCollection` for the Media being created. - -### new Media(string name, int parentId, IMediaType mediaType) - -Constructor for creating a new Media object where the necessary parameters are the name of the Media, the id of the parent as `int` and the MediaType as an `IMediaType` object for the Media being created. - -### new Media(string name, int parentId, IMediaType mediaType, IPropertyCollection properties) - -Constructor for creating a new Media object where the necessary parameters are the name of the Media, the id of the parent as `int`, the MediaType as an `IMediaType` object and a `IPropertyCollection` for the Media being created. - -## Properties - -### .CreateDate - -Gets or Sets a `DateTime` object, indicating then the given Media was created. - -```csharp -// Given a `MediaService` object get Media by its Id and return CreateDate -var media = mediaService.GetById(1234); -return media.CreateDate; -``` - -### .CreatorId - -Gets or Sets the Id of the `User` as an `int` who created the Media. - -```csharp -// Given a `MediaService` object get Media by its Id and return the Id of the Creator -var media = mediaService.GetById(1234); -return media.CreatorId; -``` - -### .ContentType - -Returns a `ISimpleContentType` object representing the ContentType used by the given `Media`. - -```csharp -// Given a `MediaService` object get Media by its Id and return MediaType -var media = mediaService.GetById(1234); -return media.ContentType; -``` - -### .ContentTypeId - -Returns the id as an `int` of the `MediaType` object representing the ContentType used by the given `Media`. - -```csharp -// Given a `MediaService` object get Media by its Id and return the Id of the MediaType -var media = mediaService.GetById(1234); -return media.ContentTypeId; -``` - -### .Id - -Returns the unique `Media` Id as a `Int`, this ID is based on a Database identity field, and is therefore not safe to reference in code which are moved between different instances, use Key instead. - -### .Key - -Returns the `Guid` assigned to the Media during creation. This value is unique, and should never change, even if the Media is moved between instances. - -```csharp -// Given a `MediaService` object get Media by its Id and return the Key -var media = mediaService.GetById(1234); -return media.Key; -``` - -### .Level - -Gets or Sets the given `Media` level in the site hierarchy as an `Int`. Media placed at the root of the tree, will return 1, Media right underneath will return 2, and so on. - -```csharp -// Given a `MediaService` object get Media by its Id and return the Level -var media = mediaService.GetById(1234); -return media.Level; -``` - -### .Name - -Gets or Sets the name of the Media as a `String`. - -```csharp -// Given a `MediaService` object get Media by its Id and return its Name -var media = mediaService.GetById(1234); -return media.Name; -``` - -### .ParentId - -Gets or Sets the parent `Media` Id as an `Int`. - -```csharp -// Given a `MediaService` object get Media by its Id and return the Id of the Parent Media -var media = mediaService.GetById(1234); -return media.ParentId; -``` - -### .Path - -Gets or Sets the path of the Media as a `String`. This string contains a comma separated list of the ancestors Ids including the current medias own id at the end of the string. - -```csharp -// Given a `MediaService` object get Media by its Id and return the Path -var media = mediaService.GetById(1234); -return media.Path; -``` - -### .Properties - -Gets or Sets the `PropertyCollection` object, which is a collection of `Property` objects. Each property corresponds to a `PropertyType`, which is defined on the `MediaType`. - -```csharp -// Given a `MediaService` object get Media by its Id and loop through all Properties -var media = mediaService.GetById(1234); -foreach(var property in media.Properties){ - string alias = property.Alias; - object value = property.GetValue(); -} -``` - -### .SortOrder - -Returns the given `Media` index, compared to sibling media. - -```csharp -// Given a `MediaService` object get Media by its Id and return its SortOrder -var media = mediaService.GetById(1234); -return media.SortOrder; -``` - -### .Trashed - -Returns a `Bool` indicating whether the given `Media` is currently in the recycle bin. - -```csharp -// Given a `MediaService` object get Media by its Id and return Trashed -var media = mediaService.GetById(1234); -return media.Trashed; -``` - -### .UpdateDate - -Gets or Sets a `DateTime` object, indicating when the given Media was last updated. - -```csharp -// Given a `MediaService` object get Media by its Id and return UpdateDate -var media = mediaService.GetById(1234); -return media.UpdateDate; -``` - -### .Version - -Returns the current Version Id as a `Guid`, For each change made to a Media item, its values are stored under a new Version. This version is identified by a `Guid`. - -## Methods - -### .ChangeContentType(IMediaType mediaType) - -Changes the `IMediaType` for the current Media object and removes PropertyTypes and Properties, which are not part of the new `MediaType`. **Please use with caution** as this remove differences between the new and old MediaType. - -```csharp -// Given a `ContentTypeService` object get the MediaType that we're changing to, -// get the Media from the `MediaService` for which we want to change MediaType for, -// and then save the Media through the MediaService. -var mediaType = contentTypeService.GetMediaType(1122); -var media = mediaService.GetById(1234); -media.ChangeContentType(mediaType); -mediaService.Save(media); -``` - -### .GetCreatorProfile() - -Gets the `IProfile` object for the Creator of this Media, which contains the Id and Name of the User who created this Media item. - -```csharp -// Given a `MediaService` object get Media by its Id and get the `IProfile` of the Creator -var media = mediaService.GetById(1234); -var profile = media.GetCreatorProfile(); -var id = profile.Id; -string name = profile.Name; -``` - -### .GetValue(string propertyTypeAlias) - -Gets the value of a Property as an `Object`. - -```csharp -// Given a `MediaService` object get Media by its Id and get a value by alias -var media = mediaService.GetById(1234); -object value = media.GetValue("height"); -int text = int.Parse(value.ToString()); -``` - -### .GetValue< TPassType >(string propertyTypeAlias) - -Gets the value of a Property as the defined type 'TPassType'. - -```csharp -// Given a `MediaService` object get Media by its Id and get a value by alias while specifying the return type -var media = mediaService.GetById(1234); -int value = media.GetValue("height"); -``` - -### .HasProperty(string propertyTypeAlias) - -Returns a `Bool` indicating whether the Media object has a property with the supplied alias. - -```csharp -// Given a `MediaService` object get Media by its Id and check if certain properties exist -var media = mediaService.GetById(1234); -bool tagsExists = media.HasProperty("myTagProperty"); -bool textExists = media.HasProperty("altText"); -``` - -### .SetValue(string propertyTypeAlias, object value) - -Sets the value of a property by its alias. - -```csharp -// Given a `MediaService` object get Media by its Id, set a few values -// and saves the Media through the `MediaService` -var media = mediaService.GetById(1234); -media.SetValue("altText", "Alternative text for this media item"); -media.SetValue("date", DateTime.Now); -mediaService.Save(media); -``` - -It is worth noting that it is also possible to pass a HttpPostedFile, HttpPostedFileBase or HttpPostedFileWrapper to the SetValue method, so it can be used for uploads. - -### .ToXml() - -Returns an `XElement` containing the Media data, based off the latest changes. When the Media item is saved the xml is stored in the database. - -```csharp -// Given a `MediaService` object get Media by its Id and returns the xml -var media = mediaService.GetById(1234); -XElement xml = media.ToXml(serializer); -return xml; -``` diff --git a/10/umbraco-cms/reference/management/models/mediatype.md b/10/umbraco-cms/reference/management/models/mediatype.md deleted file mode 100644 index 8a730821652..00000000000 --- a/10/umbraco-cms/reference/management/models/mediatype.md +++ /dev/null @@ -1,310 +0,0 @@ ---- -description: "A MediaType is almost the same as a ContentType. I.e. a model / data definition for your media nodes." ---- - -# MediaType - -A MediaType is almost the same as a [ContentType](contenttype.md), that is, a model / data definition for your media nodes - -You can set icon, thumbnail and description. It is also possible to add groups and properties. - -A Media Type differs from a Document Type in that it has no templates. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -``` - -## Constructors - -### new MediaType(IShortStringHelper shortStringHelper, int parentId) - -Constructor for creating a new `MediaType` object where the necessary parameters are a short string helper `IShortStringHelper` and the Id of the parent `MediaType` as an `Int`. - -### new MediaType(IShortStringHelper shortStringHelper,IMediaType parent) - -Constructor for creating a new `MediaType` object where the necessary parameter are a short string helper `IShortStringHelper` and the parent `MediaType` as an `IMediaType` object. - -### new MediaType(IShortStringHelper shortStringHelper, IMediaType parent, string alias) - -This constructor creates a new `MediaType` object and requires the following parameters: a short string helper `IShortStringHelper` and the parent `MediaType` as an `IMediaType` object. Additionally, the alias of the `MediaType` should be provided as a `string`. - -## Properties - -### .Alias - -Gets or Sets the Alias as a `String` of the MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return Alias -var mediaType = mediaTypeService.Get(1234); -return mediaType.Alias; -``` - -### .AllowedContentTypes - -Gets or Sets an `Enumerable` list of `ContentTypeSort` objects of the MediaTypes allowed under the current MediaType. - -The `ContentTypeSort` is an object with a lazy Id, int SortOrder and string Alias used to sort the MediaTypes within the list of AllowedContentTypes. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return AllowedContentTypes -var mediaType = mediaTypeService.Get(1234); -return mediaType.AllowedContentTypes; -``` - -### .ContentTypeComposition - -Gets a list of `MediaTypes` as `IContentTypeComposition` objects that make up a composition of PropertyGroups and PropertyTypes for the current MediaType. - -The `ContentTypeComposition` provides a mixin-type functionality in that you can compose a MediaType of one or more other MediaTypes in a complex structure. But please keep in mind that the backoffice does not fully support these complex structures yet - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return ContentTypeComposition -var mediaType = mediaTypeService.Get(1234); -return mediaType.ContentTypeComposition; -``` - -### .CompositionPropertyGroups - -Gets a list of all `PropertyGroup` objects from the composition including PropertyGroups from the current MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return CompositionPropertyGroups -var mediaType = mediaTypeService.Get(1234); -return mediaType.CompositionPropertyGroups; -``` - -### .CompositionPropertyTypes - -Gets a list of all `PropertyType` objects from the composition including PropertyTypes from the current MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return CompositionPropertyTypes -var mediaType = mediaTypeService.Get(1234); -return mediaType.CompositionPropertyTypes; -``` - -### .CreateDate - -Gets or Sets a `DateTime` object, indicating then the given MediaType was created. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return CreateDate -var mediaType = mediaTypeService.Get(1234); -return mediaType.CreateDate; -``` - -### .CreatorId - -Gets or Sets the Id of the `User` who created the MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Id of the Creator -var mediaType = mediaTypeService.Get(1234); -return mediaType.CreatorId; -``` - -### .Description - -Gets or Sets the Description as a `String` for the MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Description -var mediaType = mediaTypeService.Get(1234); -return mediaType.Description; -``` - -### .Icon - -Gets or Sets the Icon as a `String` for the MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Icon -var mediaType = mediaTypeService.Get(1234); -return mediaType.Icon; -``` - -### .Id - -Retrieves the unique `MediaType` ID as an `Int`. This ID is based on a Database identity field and is therefore not safe to reference in code when moved between different instances. - -### .Key - -Gets the `Guid` assigned to the MediaType during creation. This value is unique, and should never change, even if the content is moved between instances. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Key -var mediaType = mediaTypeService.Get(1234); -return mediaType.Key; -``` - -### .Level - -Gets or Sets the given `MediaType` level in the site hierarchy as an `Int`. MediaTypes placed at the root of the tree, will return 1, content right underneath will return 2, and so on. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Level -var mediaType = mediaTypeService.Get(1234); -return mediaType.Level; -``` - -### .Name - -Gets or Sets the name of the MediaType as a `String`. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return its Name -var mediaType = mediaTypeService.Get(1234); -return mediaType.Name; -``` - -### .ParentId - -Gets or Sets the parent `MediaType` Id as an `Int`. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Id of the Parent MediaType -var mediaType = mediaTypeService.Get(1234); -return mediaType.ParentId; -``` - -### .Path - -Gets or Sets the path of the MediaType as a `String`. This string contains a comma separated list of the ancestor Ids including the current MediaTypes own id at the end of the string. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Path -var mediaType = mediaTypeService.Get(1234); -return mediaType.Path; -``` - -### .PropertyGroups - -Gets or Sets a `PropertyGroupCollection` containing a list of PropertyGroups for the current MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return PropertyGroups -var mediaType = mediaTypeService.Get(1234); -return mediaType.PropertyGroups; -``` - -### .PropertyTypes - -Gets an `Enumerable` list of PropertyTypes aggregated for all groups within the current MediaType, as well as PropertyTypes not within a group. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return PropertyTypes -var mediaType = mediaTypeService.Get(1234); -return mediaType.PropertyTypes; -``` - -### .SortOrder - -Gets the given `MediaType` index, compared to sibling content. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return its SortOrder -var mediaType = mediaTypeService.Get(1234); -return mediaType.SortOrder; -``` - -### .Thumbnail - -Gets or Sets the Thumbnail as a `String` for the MediaType. - -```csharp -// Given a `MediaTypeService` object get MediaType by its Id and return the Thumbnail -var mediaType = mediaTypeService.Get(1234); -return mediaType.Thumbnail; -``` - -## Methods - -### .AddContentType(IContentTypeComposition mediaType) - -Adds a new `MediaType` to the list of composite MediaTypes. - -```csharp -// Given a `MediaTypeService` object get a few MediaTypes by their alias -// and add the 'Meta' and 'SEO' MediaTypes to the composition of the 'Video' MediaType. -var metaContentType = mediaTypeService.Get("meta"); -var seoContentType = mediaTypeService.Get("seo"); -var videoContentType = mediaTypeService.Get("video"); -videoContentType.AddContentType(metaContentType); -videoContentType.AddContentType(seoContentType); -mediaTypeService.Save(videoContentType); -``` - -### .CompositionAliases() - -Returns an `Enumerable` list of MediaType aliases as `String` from the current composition. - -```csharp -// Given a `MediaTypeService` object get a MediaType by its alias and loop through CompositionAliases -var mediaType = mediaTypeService.Get("video"); -var aliases = mediaType.CompositionAliases(); -foreach (var alias in aliases) -{ - string a = alias; -} -``` - -### .CompositionIds() - -Returns an `Enumerable` list of MediaType Ids as `Int` from the current composition. - -```csharp -// Given a `MediaTypeService` object get a MediaType by its alias and loop through CompositionIds -var mediaType = mediaTypeService.Get("video"); -var ids = mediaType.CompositionIds(); -foreach (var id in ids) -{ - int i = id; -} -``` - -### .ContentTypeCompositionExists(string alias) - -Checks if a `MediaType` with the supplied alias exists in the list of composite MediaTypes. - -```csharp -// Given a `MediaTypeService` object get a MediaType by its alias -// and check if a given MediaType exists in the composition of the 'Video' MediaType. -var mediaType = mediaTypeService.Get("video"); -bool result = mediaType.ContentTypeCompositionExists("meta"); -``` - -### .RemoveContentType(string alias) - -Removes a `MediaType` with the supplied alias from the list of composite MediaTypes. - -```csharp -// Given a `MediaTypeService` object get a MediaType by its alias and -// remove the 'Meta' MediaType from its composition. -var mediaType = mediaTypeService.Get("video"); -bool success = mediaType.RemoveContentType("meta"); -if (success) - mediaTypeService.Save(mediaType); -``` - -### .RemovePropertyType(string propertyTypeAlias) - -Removes a `PropertyType` from the current `MediaType`. - -```csharp -// Given a `MediaTypeService` object get a MediaType by its alias -// and remove a PropertyType from the list of PropertyTypes. -var mediaType = mediaTypeService.Get("video"); -mediaType.RemovePropertyType("uploader"); -mediaTypeService.Save(mediaType); -``` diff --git a/10/umbraco-cms/reference/management/models/relation.md b/10/umbraco-cms/reference/management/models/relation.md deleted file mode 100644 index b759017efa4..00000000000 --- a/10/umbraco-cms/reference/management/models/relation.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -description: "Represents a Relation between two items." ---- - -# Relation - -Represents a Relation between two items. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statement: - -```csharp -using Umbraco.Cms.Core.Models; -``` - -## Constructors - -### new Relation(int parentId, int childId, IRelationType relationType) - -Constructor for creating a new Relation object. The necessary parameters are the Id of the parent item as an `int`, the Id of the child as an `int` and the relationType as `IRelationType`. - -### new Relation(int parentId, int childId, Guid parentObjectType, Guid childObjectType, IRelationType relationType) - -A second constructor exists but it should not be used because it is used to reconstruct a relation from the data source. - -## Properties - -### .ChildId - -Gets or sets the Child Id of the Relation (Destination) - -```csharp -// Given a `IRelationService` object get Relation by its Id and return ChildId -var relation = relationService.GetById(1234); -return relation.ChildId; -``` - -### .Comment - -Gets or sets a comment for the Relation - -```csharp -// Given a `IRelationService` object get Relation by its Id and return Comment -var relation = relationService.GetById(1234); -return relation.Comment; -``` - -### .ParentId - -Gets or sets the Parent Id of the Relation (Source) - -```csharp -// Given a `IRelationService` object get Relation by its Id and return ParentId -var relation = relationService.GetById(1234); -return relation.ParentId; -``` - -### .RelationType - -Gets or sets the RelationType for the Relation - -```csharp -// Given a `IRelationService` object get Relation by its Id and return RelationType -var relation = relationService.GetById(1234); -return relation.RelationType; -``` - -### .RelationTypeId - -Gets the Id of the RelationType that this Relation is based on. - -```csharp -// Given a `IRelationService` object get Relation by its Id and return RelationTypeId -var relation = relationService.GetById(1234); -return relation.RelationTypeId; -``` diff --git a/10/umbraco-cms/reference/management/models/relationtype.md b/10/umbraco-cms/reference/management/models/relationtype.md deleted file mode 100644 index 4c25dbb40f7..00000000000 --- a/10/umbraco-cms/reference/management/models/relationtype.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -description: "The `RelationType` class represents a relation definition between two node types (content or media)." ---- - -# RelationType - -The `RelationType` class represents a relation definition between two node types (content or media). For example keeping track of node usage across the site, in order to avoid deleting content that is used else where. When querying a relation, it is typically done using the parent node key. However, if the `RelationType` is bidirectional, querying with the child node key is also possible. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statement: - -```csharp -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -``` - -## Constructors - -### new RelationType(string name, string alias, bool isBidrectional, Guid? parentObjectType, Guid? childObjectType) - -Create a new RelationType object with this constructor. It requires a `string` alias, the relation type's name, and a `bool` for bidirectionality. Additionally, specify the `Guid?` keys for both child and parent object types involved in the relation. - -## Properties - -### .Name - -Gets or sets the Name of the RelationType as a `String`. - -```csharp -// Given a `RelationService` object get RelationType by its Id and return Name -var relationType = relationService.GetRelationTypeById(1234); -return relationType.Name; -``` - -### .Alias - -Gets or sets the Alias of the RelationType as `String`. - -```csharp -// Given a `RelationService` object get RelationType by its Id and return Alias -var relationType = relationService.GetRelationTypeById(1234); -return relationType.Alias; -``` - -### .IsBidirectional - -Gets or sets a `boolean` indicating whether the RelationType is Bidirectional (true) or Parent to Child (false) - -```csharp -// Given a `RelationService` object get RelationType by its Id and return IsBidirectional -var relationType = relationService.GetRelationTypeById(1234); -return relationType.IsBidirectional; -``` - -### .ParentObjectType - -Gets or sets the Parents object type key as `Guid?` - -```csharp -// Given a `RelationService` object get RelationType by its Id and return ParentObjectType -var relationType = relationService.GetRelationTypeById(1234); -return relationType.ParentObjectType; -``` - -### .ChildObjectType - -Gets or sets the Childs object type key as `Guid?` - -```csharp -// Given a `RelationService` object get RelationType by its Id and return ChildObjectType -var relationType = relationService.GetRelationTypeById(1234); -return relationType.ChildObjectType; -``` diff --git a/10/umbraco-cms/reference/management/models/serverregistration.md b/10/umbraco-cms/reference/management/models/serverregistration.md deleted file mode 100644 index bbe1b61048b..00000000000 --- a/10/umbraco-cms/reference/management/models/serverregistration.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -description: "Represents a registered server in a multiple-servers environment." ---- - -# ServerRegistration - -The `ServerRegistration` class represents a registered server in a multiple-servers environment. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statement: - -```csharp -using Umbraco.Cms.Core.Models; -``` - -## Constructors - -### new ServerRegistration(string serverAddress, string serverIdentity, DateTime registered) - -Constructor for creating a new ServerRegistration object. The necessary parameters are the serverAddress as a `string`, the serverIdentity as a `string` and the date and time of registration as a `DateTime` - -### new ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isSchedulingPublisher) - -A second constructor exists but it should not be used because it is used to reconstruct a `ServerRegistration` from the data source. - -## Properties - -### .Accessed - -Gets the date and time the registration was last accessed. - -```csharp -// Given a `IServerRegistrationService` object get the first ServerRegistration and return Accessed -var serverRegistration = serverRegistrationService.GetActiveServers().FirstOrDefault(); -return serverRegistration.Accessed; -``` - -### .IsActive - -Gets or sets a value indicating whether the server is active. - -```csharp -// Given a `IServerRegistrationService` object get the first ServerRegistration and return IsActive -var serverRegistration = serverRegistrationService.GetActiveServers().FirstOrDefault(); -return serverRegistration.IsActive; -``` - -### .IsSchedulingPublisher - -Gets or sets a value indicating whether the server has the SchedulingPublisher role - -```csharp -// Given a `IServerRegistrationService` object get the first ServerRegistration and return IsSchedulingPublisher -var serverRegistration = serverRegistrationService.GetActiveServers().FirstOrDefault(); -return serverRegistration.IsSchedulingPublisher; -``` - -### .Registered - -Gets the date and time the registration was created. - -```csharp -// Given a `IServerRegistrationService` object get the first ServerRegistration and return Registered -var serverRegistration = serverRegistrationService.GetActiveServers().FirstOrDefault(); -return serverRegistration.Registered; -``` - -### .ServerAddress - -Gets or sets the server URL. - -```csharp -// Given a `IServerRegistrationService` object get the first ServerRegistration and return ServerAddress -var serverRegistration = serverRegistrationService.GetActiveServers().FirstOrDefault(); -return serverRegistration.ServerAddress; -``` - -### .ServerIdentity - -Gets or sets the server unique identity. - -```csharp -// Given a `IServerRegistrationService` object get the first ServerRegistration and return ServerIdentity -var serverRegistration = serverRegistrationService.GetActiveServers().FirstOrDefault(); -return serverRegistration.ServerIdentity; -``` diff --git a/10/umbraco-cms/reference/management/models/template.md b/10/umbraco-cms/reference/management/models/template.md deleted file mode 100644 index 57005bdb91d..00000000000 --- a/10/umbraco-cms/reference/management/models/template.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -description: "Represents a Template file." ---- - -# Template - -Represents a Template file. - -* **Namespace:** `Umbraco.Cms.Core.Models` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Models; -``` - -## Constructors - -### new Template(IShortStringHelper shortStringHelper, string name, string alias) - -Constructor for creating a new Template object. The necessary parameters include a short String Helper as an `IShortStringHelper`. The name and alias of the Template must be provided as `string` values. - -## Properties - -### .Alias - -Gets the Alias of the File, which is the name without the extension. - -```csharp -var template = new Template(shortStringHelper, "Page", "page"); -return template.Alias; -``` - -### .IsMasterTemplate - -Returns true if the template is used as a layout for other templates (that is, it has 'children') - -```csharp -var template = new Template(shortStringHelper,"Page", "page"); -return template.IsMasterTemplate; -``` - -### .MasterTemplateAlias - -Returns the alias of the master template if one is set. - -```csharp -var template = new Template(shortStringHelper, "Page", "page"); -return template.MasterTemplateAlias; -``` - -### .MasterTemplateId - -Returns the id of the master template if one is set. - -```csharp -var template = new Template(shortStringHelper, "Page", "page"); -return template.MasterTemplateId; -``` - -### .Name - -Gets the Name of the File including extension. - -```csharp -var template = new Template(shortStringHelper, "Page", "page"); -return template.Name; -``` - -## Methods - -### .SetMasterTemplate(ITemplate masterTemplate) - -Sets the master template of the template. - -```csharp -// Create a new template -var template = new Template(shortStringHelper, "Page", "page"); -// Get a master template -var masterTemplate = fileService.GetTemplate(1234); -// Set the master template to new created template -template.SetMasterTemplate(masterTemplate); -// Save the new template -fileService.SaveTemplate(template); -``` diff --git a/10/umbraco-cms/reference/management/services/README.md b/10/umbraco-cms/reference/management/services/README.md deleted file mode 100644 index e30a9cdeb9d..00000000000 --- a/10/umbraco-cms/reference/management/services/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Services Reference - diff --git a/10/umbraco-cms/reference/management/services/auditservice.md b/10/umbraco-cms/reference/management/services/auditservice.md deleted file mode 100644 index d2eb4b6c756..00000000000 --- a/10/umbraco-cms/reference/management/services/auditservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# AuditService - -The AuditService acts as a "gateway" to Umbraco data for operations which are related to the audit trail. - -[Browse the API documentation for IAuditService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IAuditService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the audit service in a class, you need to use Dependency Injection (DI). For instance if you have registered your own class in Umbraco's DI container, you can specify the `IAuditService` interface in your constructor: - -```csharp -public class MyClass -{ - private IAuditService _auditService; - - public MyClass(IAuditService auditService) - { - _auditService = auditService; - } -} -``` - -In Razor views, you can access the audit service through the `@inject` directive: - -```csharp -@inject IAuditService AuditService -``` diff --git a/10/umbraco-cms/reference/management/services/consentservice.md b/10/umbraco-cms/reference/management/services/consentservice.md deleted file mode 100644 index 78f70243bb2..00000000000 --- a/10/umbraco-cms/reference/management/services/consentservice.md +++ /dev/null @@ -1,56 +0,0 @@ -# ConsentService - -**Applies to Umbraco 9 and newer** - -[Browse the API documentation for ConsentService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IConsentService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -A service for handling lawful data processing requirements. - -## What is a Consent - -A consent is fully identified by a source (whoever is consenting), a context (for example, an application), and an action (whatever is consented). A consent state registers the state of the consent (granted, revoked...). - -## Register a new consent - -Consent can be given or revoked or changed via the `RegisterConsent` method, which creates a new `Consent` entity to track the consent. - -## Get the current state - -Getter methods of this service return the current state of a consent, that is the latest [IConsent](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Models.IConsent.html) entity that was created. - -## Revoking a consent - -Revoking a consent is performed by registering a revoked consent. - -A consent _cannot be deleted_. It can only be revoked by registering a "revoked consent". - -## Examples - -``` -// store a new consent -var newConsent = _consentService.RegisterConsent("userId", "Our.Custom.Umbraco.Plugin", "AllowedToEmail", ConsentState.Granted, "some comments"); - -// lookup a consent -var consents = _consentService.LookupConsent("userId", "Our.Custom.Umbraco.Plugin", "AllowedToEmail", sourceStartsWith : true); -if (consents != null && consents.Any()) -{ - var currentConsent = consents.First(c => c.Current == true); - if(currentConsent.State == ConsentState.Granted) - { - // Do what you need - } - else - { - // the state is None, Pending or Revoked - } -} -``` - -In Razor views, you can access the consent service through the `@inject` directive: - -```csharp -@inject IConsentService ConsentService -``` diff --git a/10/umbraco-cms/reference/management/services/contentservice/README.md b/10/umbraco-cms/reference/management/services/contentservice/README.md deleted file mode 100644 index 4f691b40b9a..00000000000 --- a/10/umbraco-cms/reference/management/services/contentservice/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# ContentService - -The ContentService acts as a "gateway" to Umbraco data for operations which are related to Content. - -[Browse the v9 API documentation for ContentService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IContentService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -If you wish to use the content service in a class, you need to use Dependency Injection (DI) in your constructor: - -```csharp -public class MyClass -{ - private IContentService _contentService; - - public MyClass(IContentService contentService) - { - _contentService = contentService; - } -} -``` - -In Razor views, you can access the content service through the `@inject` directive: - -```csharp -@inject IContentService ContentService -``` diff --git a/10/umbraco-cms/reference/management/services/contentservice/create-content-programmatically.md b/10/umbraco-cms/reference/management/services/contentservice/create-content-programmatically.md deleted file mode 100644 index 862a419edc5..00000000000 --- a/10/umbraco-cms/reference/management/services/contentservice/create-content-programmatically.md +++ /dev/null @@ -1,24 +0,0 @@ -# Create content programmatically - -In the example below, a new page is programmatically created using the content service. It is assumed that there are two document types, namely people and person. In this case, a new person is added underneath the people page. - -```csharp -// Get access to ContentService -var contentService = Services.ContentService; - -// Create a variable for the GUID of the parent where you want to add a child item. -// In this case the people page. -var parentId = Guid.Parse("b6fbbb31-a77f-4f9c-85f7-2dc4835c7f31"); - -// Create a new child item of type 'person' -var person = contentService.Create("James", parentId, "person"); - -// Set the value of the property with alias 'email' -person.SetValue("email" , "james@contact.com"); - -// Set the value of the property with alias 'isAuthor' -person.SetValue("isAuthor", false); - -// Save the child item -contentService.Save(person); -``` diff --git a/10/umbraco-cms/reference/management/services/contenttypeservice/README.md b/10/umbraco-cms/reference/management/services/contenttypeservice/README.md deleted file mode 100644 index abf516d7ef5..00000000000 --- a/10/umbraco-cms/reference/management/services/contenttypeservice/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# ContentTypeService - -The content type service acts as a "gateway" to Umbraco data for operations which are related to both content types and media types. - -[Browse the API documentation for IContentTypeService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IContentTypeService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the content type service in a class, you need to specify the `IContentTypeService` interface in your constructor: - -```csharp -public class MyClass -{ - private IContentTypeService _contentTypeService; - - public MyClass(IContentTypeService contentTypeService) - { - _contentTypeService = contentTypeService; - } -} -``` - -In Razor views, you can access the content type service through the `@inject` directive: - -```csharp -@inject IContentTypeService ContentTypeService -``` - -## Samples - -* [**Retrieving content types**](retrieving-content-types.md)\ - See examples on how to retrieve content types via the service - either individually or as a collection. -* [**Retrieving content type containers**](retrieving-content-type-containers.md)\ - See examples on how to retrieve content type containers (folders) via the service - either individually or as a collection. diff --git a/10/umbraco-cms/reference/management/services/contenttypeservice/retrieving-content-type-containers.md b/10/umbraco-cms/reference/management/services/contenttypeservice/retrieving-content-type-containers.md deleted file mode 100644 index b76867c6722..00000000000 --- a/10/umbraco-cms/reference/management/services/contenttypeservice/retrieving-content-type-containers.md +++ /dev/null @@ -1,42 +0,0 @@ -# Retrieving content types - -## Getting a single content type container - -Content types can be added either at the root level, under another content type or under a content type container (or folders as they're called in the Umbraco backoffice). The approach for getting a single container is similar to getting a single content type, meaning that you can look up a container - either by its GUID: - -``` -// Declare the GUID ID -Guid guid = new Guid("d3b9cc9a-d471-4465-a89a-112c6bc1e5b4"); - -// Get a container by its GUID ID -EntityContainer container = _contentTypeService.GetContainer(guid); -``` - -or its numeric counterpart: - -``` -// Get a container by its numeric ID -EntityContainer container = _contentTypeService.GetContainer(1090); -``` - -## Getting a list of content type containers - -In the same way as you can get the content types of a container, you can get the child containers of another container. This is done by calling the `GetContainers` method with an array of numeric IDs: - -``` -// Declare the array of IDs to lookup -int[] ids = new[] {1090}; - -// Get the child containers via the content type service -IEnumerable containers = _contentTypeService.GetContainers(ids); -``` - -Also, if the array is empty, all containers will be returned: - -``` -// Declare the array of IDs to lookup -int[] ids = new int[0]; - -// Get all content type containers -IEnumerable containers = _contentTypeService.GetContainers(ids); -``` diff --git a/10/umbraco-cms/reference/management/services/contenttypeservice/retrieving-content-types.md b/10/umbraco-cms/reference/management/services/contenttypeservice/retrieving-content-types.md deleted file mode 100644 index c6536b9cc67..00000000000 --- a/10/umbraco-cms/reference/management/services/contenttypeservice/retrieving-content-types.md +++ /dev/null @@ -1,78 +0,0 @@ -# Retrieving content types - -## Getting a single content type - -A given content type has a few different unique identifier that we can use to look it up via the content type service. For instance, if we know the GUID of the content type, we can look it up like this: - -``` -// Declare the GUID ID -Guid guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); - -// Get a reference to the content type by its GUID ID -IContentType contentType = _contentTypeService.Get(guid); -``` - -Although the use of a GUID is preferable, you can also use it's numeric ID: - -``` -// Get a reference to the content type by its numeric ID -IContentType contentType = _contentTypeService.Get(1234); -``` - -Finally, you can also look up a content type by its alias: - -``` -// Get a reference to the content type by its alias -IContentType contentType = _contentTypeService.Get("home"); -``` - -## Getting a list of content types - -As content types are stored in a hierarchical list with folders (containers), there is also multiple ways to can get content types. If you are looking for a flat list of all content types, you can use the `GetAll` method: - -``` -// Get a collection of all content types -IEnumerable contentTypes = _contentTypeService.GetAll(); -``` - -In the example above, the method was called without any parameters. The method also has two overloads, which lets you look up a collection fo content types by either specifying their GUID or numeric IDs: - -``` -// Get a collection of two specific content types by their GUIDs IDs -IEnumerable contentTypes = _contentTypeService.GetAll(new[] { - new Guid("2b54088e-d355-4b9e-aa4b-5aec4b3f87eb"), - new Guid("859c5916-19d8-4a72-9bd0-5641ad503aa9") -}); -``` - -``` -// Get a collection of two specific content types by their numeric IDs -IEnumerable contentTypes = _contentTypeService.GetAll(1234, 1235); -``` - -To get a list of all content types of another content type, you can instead use the `GetChildren` method - either by specifying the numeric ID or the GUID: - -``` -// Get a collection of content types of a specific content type -IEnumerable contentTypes = _contentTypeService.GetChildren(1232); -``` - -``` -IEnumerable contentTypes = _contentTypeService.GetChildren(Guid.Parse("4f89dd28-d038-4209-aaa1-06109b7946a7")); -``` - -## Check whether a content type has children - -In some cases it can be useful to check if a content type has children. The `HasChildren` method can be used to check whether a content type has children. - -```csharp -// Check if there are children -bool hasChildren = _contentTypeService.HasChildren(Guid.Parse("2b54088e-d355-4b9e-aa4b-5aec4b3f87eb")); -``` - -Although the use of a GUID is preferable, you can also use it's numeric ID: - -```csharp -// Check if there are children -bool hasChildren = _contentTypeService.HasChildren(1234); -``` diff --git a/10/umbraco-cms/reference/management/services/datatypeservice.md b/10/umbraco-cms/reference/management/services/datatypeservice.md deleted file mode 100644 index 81686cef7c5..00000000000 --- a/10/umbraco-cms/reference/management/services/datatypeservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# DataTypeService - -The DataTypeService acts as a "gateway" to Umbraco data for operations which are related to DataTypes and DataTypeDefinitions. - -[Browse the API documentation for IDataTypeService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IDataTypeService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the Data Type service in a class, you need to specify the `IDataTypeService` interface in your constructor: - -``` -public class MyClass -{ - private IDataTypeService _dataTypeService; - - public MyClass(IDataTypeService dataTypeService) - { - _dataTypeService = dataTypeService; - } -} -``` - -In Razor views, you can access the Data Type service through the `@inject` directive: - -```csharp -@inject IDataTypeService DataTypeService -``` diff --git a/10/umbraco-cms/reference/management/services/domainservice.md b/10/umbraco-cms/reference/management/services/domainservice.md deleted file mode 100644 index 2187f068b65..00000000000 --- a/10/umbraco-cms/reference/management/services/domainservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# DomainService - -The DomainService acts as a "gateway" to Umbraco data for operations which are related to domains. - -[Browse the API documentation for IDomainService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IDomainService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the domain service in a class, you need to specify the `IDomainService` interface in your constructor: - -```csharp -public class MyClass -{ - private IDomainService _domainService; - - public MyClass(IDomainService domainService) - { - _domainService = domainService; - } -} -``` - -In Razor views, you can access the domain service through the `@inject` directive: - -```csharp -@inject IDomainService DomainService -``` diff --git a/10/umbraco-cms/reference/management/services/entityservice.md b/10/umbraco-cms/reference/management/services/entityservice.md deleted file mode 100644 index 420da5e58d0..00000000000 --- a/10/umbraco-cms/reference/management/services/entityservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# EntityService - -The EntityService acts as a "gateway" to Umbraco data for operations which are related to entities. - -[Browse the API documentation for IEntityService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IEntityService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the entity service in a class, you need to specify the `IEntityService` interface in your constructor: - -```csharp -public class MyClass -{ - private IEntityService _entityService; - - public MyClass(IEntityService entityService) - { - _entityService = entityService; - } -} -``` - -In Razor views, you can access the entity service through the `@inject` directive: - -```csharp -@inject IEntityService EntityService -``` diff --git a/10/umbraco-cms/reference/management/services/externalloginservice.md b/10/umbraco-cms/reference/management/services/externalloginservice.md deleted file mode 100644 index dbf67ef8fa9..00000000000 --- a/10/umbraco-cms/reference/management/services/externalloginservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# ExternalLoginService - -The ExternalLoginService is used to store the external login info and can be replaced with your own implementation. - -[Browse the API documentation for IEntityService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IExternalLoginService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the entity service in a class, you need to specify the `IExternalLoginService` interface in your constructor: - -```csharp -public class MyClass -{ - private IExternalLoginService _externalLoginService; - - public MyClass(IExternalLoginService externalLoginService) - { - _externalLoginService = externalLoginService; - } -} -``` - -In Razor views, you can access the entity service through the `@inject` directive: - -```csharp -@inject IExternalLoginService ExternalLoginService -``` \ No newline at end of file diff --git a/10/umbraco-cms/reference/management/services/fileservice.md b/10/umbraco-cms/reference/management/services/fileservice.md deleted file mode 100644 index 163769afbe9..00000000000 --- a/10/umbraco-cms/reference/management/services/fileservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# FileService - -The FileService acts as a "gateway" to Umbraco data for operations which are related to Scripts, Stylesheets and Templates. - -[Browse the API documentation for IFileService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IFileService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the file service in a class, you need to specify the `IFileService` interface in your constructor: - -```csharp -public class MyClass -{ - private IFileService _fileService; - - public MyClass(IFileService fileService) - { - _fileService = fileService; - } -} -``` - -In Razor views, you can access the file service through the `@inject` directive: - -```csharp -@inject IFileService FileService -``` diff --git a/10/umbraco-cms/reference/management/services/images/relations-api.PNG b/10/umbraco-cms/reference/management/services/images/relations-api.PNG deleted file mode 100644 index a9a39ed6b55..00000000000 Binary files a/10/umbraco-cms/reference/management/services/images/relations-api.PNG and /dev/null differ diff --git a/10/umbraco-cms/reference/management/services/images/relations.PNG b/10/umbraco-cms/reference/management/services/images/relations.PNG deleted file mode 100644 index e446f442f5e..00000000000 Binary files a/10/umbraco-cms/reference/management/services/images/relations.PNG and /dev/null differ diff --git a/10/umbraco-cms/reference/management/services/localizationservice/README.md b/10/umbraco-cms/reference/management/services/localizationservice/README.md deleted file mode 100644 index bd599b881f0..00000000000 --- a/10/umbraco-cms/reference/management/services/localizationservice/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# LocalizationService - -The LocalizationService acts as a "gateway" to Umbraco data for operations which are related to Dictionary items and Languages. - -[Browse the API documentation for ILocalizationService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.ILocalizationService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the localization service in a class, you need to specify the `ILocalizationService` interface in your constructor: - -``` -public class MyClass -{ - private ILocalizationService _localizationService; - - public MyClass(ILocalizationService localizationService) - { - _localizationService = localizationService; - } -} -``` - -In Razor views, you can access the localization service through the `@inject` directive: - -```csharp -@inject ILocalizationService LocalizationService -``` - -## Samples - -* [**Retrieving languages**](retrieving-languages.md)\ - See examples on how to retrieve languages via the localization service - either individually or as a collection. diff --git a/10/umbraco-cms/reference/management/services/localizationservice/retrieving-languages.md b/10/umbraco-cms/reference/management/services/localizationservice/retrieving-languages.md deleted file mode 100644 index 8886d64161a..00000000000 --- a/10/umbraco-cms/reference/management/services/localizationservice/retrieving-languages.md +++ /dev/null @@ -1,88 +0,0 @@ -# Retrieving languages - -### Getting a single language - -The localization service contains a number of methods for looking up languages. If you already know the ID of a specific language (eg. the default language has ID `1`), you can use the `GetLanguageById` method to get the reference to that language: - -``` -// Get a reference to the language by its ID -ILanguage language1 = _localizationService.GetLanguageById(1); -``` - -Alternative, you can look up a language by its iso code via the `GetLanguageByIsoCode` method: - -``` -// Get a reference to the language by its ISO code -ILanguage language2 = _localizationService.GetLanguageByIsoCode("en-US"); -``` - -The ISO code is a combination of the two-letter ISO 639-1 language code (lowercase) and two-letter ISO-3166 country code (uppercase). Eg. `en-US` for English in the United States, `en-GB` for English in the United Kingdom and `da-DK` for Danish in Denmark. - -Both methods will return an instance of the [ILanguage](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Models.ILanguage.html) interface, which has traditional properties like `Id` and `Key`, but also properties specific to the language like `CultureName`, `CultureInfo` and `IsoCode`. You can see the API reference for further information on the properties of the interface. - -### Getting all languages - -If you need instead need a list of all installed languages, you can use the `GetAllLanguages` method. It takes no parameters, and as such a returns a collection of all languages (with no pagination like some of the other services): - -``` -// Get a collection of all languages -IEnumerable languages = _localizationService.GetAllLanguages(); - -// Iterate over the collection -foreach (ILanguage language in languages) -{ - // Get the .NET culture info - CultureInfo cultureInfo = language.CultureInfo; - -

ID: @language.Id
-
Key: @language.Key
-
Name: @language.CultureName
-
ISO: @language.IsoCode
-
Culture info: @cultureInfo
-
-} -``` - -As shown in the example above, you can get the `System.Globalization.CultureInfo` instance of each language, which determines how numbers, dates and similar should be either parsed or formatted in .NET. - -## Full example - -Below you can see a full example of the examples shown above - including the necessary imports: - -``` -@using System.Globalization -@using Umbraco.Cms.Core.Models -@using Umbraco.Cms.Core.Services -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@inject ILocalizationService LocalizationService - -@{ - // Get a collection of all languages - IEnumerable languages = LocalizationService.GetAllLanguages(); - - // Iterate over the collection - foreach (ILanguage language in languages) - { - - // Get the .NET culture info - CultureInfo cultureInfo = language.CultureInfo; - -
ID: @language.Id
-
Key: @language.Key
-
Name: @language.CultureName
-
ISO: @language.IsoCode
-
Culture info: @cultureInfo
-
- - } - - // Get a reference to the language by its ID - ILanguage language1 = LocalizationService.GetLanguageById(1); - - // Get a reference to the language by its ISO code - ILanguage language2 = LocalizationService.GetLanguageByIsoCode("en-US"); - -
@language1
-
@language2
-} -``` diff --git a/10/umbraco-cms/reference/management/services/macroservice.md b/10/umbraco-cms/reference/management/services/macroservice.md deleted file mode 100644 index 4bc757b235a..00000000000 --- a/10/umbraco-cms/reference/management/services/macroservice.md +++ /dev/null @@ -1,46 +0,0 @@ -# MacroService - -Defines the MacroService, which is an access to operations involving `IMacro`. - -[Browse the API documentation for IMacroService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IMacroService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the macro service in a class, you need to specify the `IMacroService` interface in your constructor: - -```csharp -public class MyClass -{ - private IMacroService _macroService; - - public MyClass(IMacroService macroService) - { - _macroService = macroService; - } -} -``` - -In Razor views, you can access the macro service through the `@inject` directive: - -```csharp -@inject IMacroService MacroService -``` diff --git a/10/umbraco-cms/reference/management/services/mediaservice.md b/10/umbraco-cms/reference/management/services/mediaservice.md deleted file mode 100644 index f1b6adc24cd..00000000000 --- a/10/umbraco-cms/reference/management/services/mediaservice.md +++ /dev/null @@ -1,115 +0,0 @@ -# MediaService - -The MediaService acts as a "gateway" to Umbraco data for operations which are related to media. - -[Browse the API documentation for IMediaService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IMediaService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require reference to the following packages: - -* [`Umbraco.Cms.Core`](https://www.nuget.org/packages/Umbraco.Cms.Core/) - -Samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Extensions; -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the media service in a class, you need to specify the `IMediaService` interface in your constructor: - -```csharp -public class MyClass -{ - private IMediaService _mediaService; - - public MyClass(IMediaService mediaService) - { - _mediaService = mediaService; - } -} -``` - -In Razor views, you can access the media service through the `@inject` directive: - -```csharp -@inject IMediaService MediaService -``` - -## Samples - -### Creating a new folder - -To create a new folder at the root of the media archive, your code could look like the following: - -```csharp -// Initialize a new media at the root of the media archive -IMedia folder = _mediaService.CreateMedia("Samples Media Item Folder", Constants.System.Root, Constants.Conventions.MediaTypes.Folder); - -// Save the folder -var result = _mediaService.Save(folder); -``` - -Alternatively, you can replace the Constants in the above sample with hardcoded values. - -```csharp -// Initialize a new media at the root of the media archive -IMedia folder = _mediaService.CreateMedia("Samples Media Item Folder", -1, "Folder"); - -// Save the folder -var result = _mediaService.Save(folder); -``` - -For the `CreateMedia` method, the first parameter is the name of the folder to be created. - -The second parameter is the ID of the parent media item. `Constants.System.Root` is a constant defined in Umbraco with the value of `-1`, which is used for indicating the root of the media archive. Instead of specifying the numeric ID of the parent, you may instead specify either a `Guid` ID or an `IMedia` instance representing the parent media. - -The third parameter is the alias of the Media Type. As Umbraco comes with a Folder Type by default, we can use the `Constants.Conventions.MediaTypes.Folder` constant to specify that the alias of the Media Type is `Folder`. - -Besides the three mandatory parameters, you can specify a user's numeric ID for media creation attribution. Unspecified cases default to the "Administrator" user with ID `-1`. - -### Creating a new media item from a stream - -You can specify a `Stream` for the contents of the file that should be created. - -As an example, if you have an image on disk named `unicorn.jpg` in the images folder of `wwwroot`. You can open a new stream for a file on the disk, and then create a new media item for that file in Umbraco: - -Please be aware that you will need to inject the following services: - -* `MediaFileManager _mediaFileManager` -* `IShortStringHelper _shortStringHelper` -* `IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider` -* `MediaUrlGeneratorCollection _mediaUrlGeneratorCollection` -* `IMediaService _mediaService` -* `IWebHostEnvironment _webHostEnvironment` - -```csharp -string webRootPath = _webHostEnvironment.WebRootPath; -var path = Path.Combine(webRootPath, "images", "unicorn.jpg"); - -// Open a new stream to the file -using (Stream stream = System.IO.File.OpenRead(path)) -{ - // Initialize a new image at the root of the media archive - IMedia media = _mediaService.CreateMedia("Unicorn", Constants.System.Root, Constants.Conventions.MediaTypes.Image); - // Set the property value (Umbraco will handle the underlying magic) - media.SetValue(_mediaFileManager, _mediaUrlGeneratorCollection, _shortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File, "unicorn.jpg", stream); - - // Save the media - var result = _mediaService.Save(media); -} -} -``` - -Again Umbraco will make sure the necessary properties are updated. diff --git a/10/umbraco-cms/reference/management/services/membergroupservice.md b/10/umbraco-cms/reference/management/services/membergroupservice.md deleted file mode 100644 index 4cabd9621bf..00000000000 --- a/10/umbraco-cms/reference/management/services/membergroupservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# MemberGroupService - -The MemberGroupService acts as a "gateway" to Umbraco data for operations which are related to Member groups, which are also known as Member Roles. - -[Browse the API documentation for IMemberGroupService](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IMemberGroupService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the member group service in a class, you need to specify the `IMemberGroupService` interface in your constructor: - -```csharp -public class MyClass -{ - private IMemberGroupService _memberGroupService; - - public MyClass(IMemberGroupService memberGroupService) - { - _memberGroupService = memberGroupService; - } -} -``` - -In Razor views, you can access the member group service through the `@inject` directive: - -```csharp -@inject IMemberGroupService MemberGroupService -``` diff --git a/10/umbraco-cms/reference/management/services/memberservice.md b/10/umbraco-cms/reference/management/services/memberservice.md deleted file mode 100644 index a0786839752..00000000000 --- a/10/umbraco-cms/reference/management/services/memberservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# MemberService - -The MemberService acts as a "gateway" to Umbraco data for operations which are related to Members. - -[Browse the API documentation for IMemberService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IMemberService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the member service in a class, you need to specify the `IMemberService` interface in your constructor: - -```csharp -public class MyClass -{ - private IMemberService _memberService; - - public MyClass(IMemberService memberService) - { - _memberService = memberService; - } -} -``` - -In Razor views, you can access the member service through the `@inject` directive: - -```csharp -@inject IMemberService MemberService -``` diff --git a/10/umbraco-cms/reference/management/services/membertypeservice.md b/10/umbraco-cms/reference/management/services/membertypeservice.md deleted file mode 100644 index 91b4b5a981f..00000000000 --- a/10/umbraco-cms/reference/management/services/membertypeservice.md +++ /dev/null @@ -1,48 +0,0 @@ -# MemberTypeService - -The MemberTypeService acts as a "gateway" to Umbraco data for operations which are related to MemberTypes. - -[Browse the API documentation for IMemberTypeService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IMemberTypeService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the member type service in a class, you need to specify the `IMemberTypeService` interface in your constructor: - -```csharp -public class MyClass -{ - private IMemberTypeService _memberTypeService; - - public MyClass(IMemberTypeService memberTypeService) - { - _memberTypeService = memberTypeService; - } -} -``` - -In Razor views, you can access the member type service through the `@inject` directive: - -```csharp -@inject IMemberTypeService MemberTypeService -``` diff --git a/10/umbraco-cms/reference/management/services/notificationservice.md b/10/umbraco-cms/reference/management/services/notificationservice.md deleted file mode 100644 index 74bae04a761..00000000000 --- a/10/umbraco-cms/reference/management/services/notificationservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# NotificationService - -The NotificationServices is used to perform operations related to backoffice notifications. - -[Browse the API documentation for INotificationService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.INotificationService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `INotificationService` interface in your constructor: - -```csharp -public class MyClass -{ - private INotificationService _notificationService; - - public MyClass(INotificationService notificationService) - { - _notificationService = notificationService; - } -} -``` - -In Razor views, you can access the member type service through the `@inject` directive: - -```csharp -@inject INotificationService NotificationService -``` \ No newline at end of file diff --git a/10/umbraco-cms/reference/management/services/packagingservice.md b/10/umbraco-cms/reference/management/services/packagingservice.md deleted file mode 100644 index b72688397ae..00000000000 --- a/10/umbraco-cms/reference/management/services/packagingservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# PackagingService - -The PackagingService provides import/export functionality for the Core models of the API. - -[Browse the API documentation for IPackagingService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IPackagingService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `IPackagingService` interface in your constructor: - -```csharp -public class MyClass -{ - private IPackagingService _packagingService; - - public MyClass(IPackagingService packagingService) - { - _packagingService = packagingService; - } -} -``` - -In Razor views, you can access the member service through the `@inject` directive: - -```csharp -@inject IPackagingService PackagingService -``` diff --git a/10/umbraco-cms/reference/management/services/publicaccessservice.md b/10/umbraco-cms/reference/management/services/publicaccessservice.md deleted file mode 100644 index 3d5edbfb08a..00000000000 --- a/10/umbraco-cms/reference/management/services/publicaccessservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# PublicAccessService - -Service to handle public access. - -[Browse the API documentation for IPublicAccessService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IPublicAccessService.html). - - * **Namespace:** `Umbraco.Cms.Core.Services` - * **Assembly:** `Umbraco.Core.dll` - - All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `IPublicAccessService` interface in your constructor: - -```csharp -public class MyClass -{ - private IPublicAccessService _publicAccessService; - - public MyClass(IPublicAccessService publicAccessService) - { - _publicAccessService = publicAccessService; - } -} -``` - -In Razor views, you can access the member service through the `@inject` directive: - -```csharp -@inject IPublicAccessService PublicAccessService -``` diff --git a/10/umbraco-cms/reference/management/services/redirecturlservice.md b/10/umbraco-cms/reference/management/services/redirecturlservice.md deleted file mode 100644 index 89919200112..00000000000 --- a/10/umbraco-cms/reference/management/services/redirecturlservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# RedirectUrlService - -The RedirectUrlService is used for CRUD operations related to Redirects. - -[Browse the API documentation for IRedirectUrlService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IRedirectUrlService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `IRedirectUrlService` interface in your constructor: - -```csharp -public class MyClass -{ - private IRedirectUrlService _redirectUrlService; - - public MyClass(IRedirectUrlService redirectUrlService) - { - _redirectUrlService = redirectUrlService; - } -} -``` - -In Razor views, you can access the member service through the `@inject` directive: - -```csharp -@inject IRedirectUrlService RedirectUrlService -``` \ No newline at end of file diff --git a/10/umbraco-cms/reference/management/services/relationservice.md b/10/umbraco-cms/reference/management/services/relationservice.md deleted file mode 100644 index dfc4f89874e..00000000000 --- a/10/umbraco-cms/reference/management/services/relationservice.md +++ /dev/null @@ -1,456 +0,0 @@ -# RelationService - -The `RelationService` is pretty awesome as it allows you to create relations between objects that would otherwise have no obvious connection. - -[Browse the API documentation for IRelationService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.IRelationService.html). - -* **Namespace:** `Umbraco.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -## Getting the service - -When you are using an Umbraco controller class (Such as `SurfaceController` or `RenderMvcController`) you have access to the `RelationService` through the `ServiceContext`: - -```csharp -using System.Web.Mvc; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; - -namespace Doccers.Core.Controllers -{ - public class HomeController : RenderMvcController - { - public ActionResult Home(ContentModel model) - { - var rs = Services.RelationService; - - return CurrentTemplate(model); - } - } -} -``` - -You can also use the `RelationService` in any other class by injecting its interface: - -```csharp -using Umbraco.Core.Composing; -using Umbraco.Core.Services; - -namespace Doccers.Core.Components -{ - public class RelationComponent : IComponent - { - private readonly IRelationService _relationService; - - public RelationComponent(IRelationService relationService) - { - _relationService = relationService; - } - - public void Initialize() { } - - public void Terminate() { } - } -} -``` - -## Methods - -### AreRelated(int parentId, int childId, string relationTypeAlias) - -Checks if two items are related. - -Returns `bool`. - -### AreRelated(IUmbracoEntity parent, IUmbracoEntity child, string relationTypeAlias) - -Checks if two items are related. - -Returns `bool`. - -### AreRelated(int parentId, int childId) - -Checks if two items are related. - -Returns `bool`. - -### Delete(IRelation relation) - -Deletes a relation. - -Returns `void`. - -### Delete(IRelationType relationType) - -Deletes a relation type. - -Returns `void`. - -### DeleteRelationsOfType(IRelationType relationType) - -Deletes relation of the specified relation type. - -Returns `void`. - -### GetAllRelations(params int\[] ids) - -Gets a collection of `Umbraco.Core.Models.Relation` objects. Optional array of integer ids to return relations for. - -Returns `IEnumerable`. - -### GetAllRelationsByRelationType(RelationType relationType) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their relation type. - -Returns `IEnumerable`. - -### GetAllRelationsByRelationType(int relationTypeId) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their relation type id. - -Returns `IEnumerable`. - -### GetAllRelationTypes(params int\[] ids) - -Gets a collection of `Umbraco.Core.Models.Relation` objects. Optional array of integer ids to return relationtypes for. - -Returns `IEnumerable`. - -### GetByChild(IUmbracoEntity child) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their child entity. - -Returns `IEnumerable`. - -### GetByChild(IUmbracoEntity child, string relationTypeAlias) - -Gets a collection of `Umbraco.Core.Models.Relation` objects their child entity and relation type alias. - -Returns `IEnumerable`. - -### GetByChildId(int id) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their child id. - -Returns `IEnumerable`. - -### GetById(int id) - -Gets a `Umbraco.Core.Models.Relation` object by its id. - -Returns `IRelation`. - -### GetByParent(IUmbracoEntity parent, string relationTypeAlias) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their parent entity and relation type alias. - -Returns `IEnumerable`. - -### GetByParent(IUmbracoEntity parent) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their parent entity. - -Returns `IEnumerable`. - -### GetByParentId(int id) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their parent id. - -Returns `IEnumerable`. - -### GetByParentOrChildId(int id, string relationTypeAlias) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their parent or child id and relation type alias. - -Returns `IEnumerable`. - -{% hint style="info" %} -Using this method will get you all relations regards of it being a child or parent relation. -{% endhint %} - -### GetByParentOrChildId(int id) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their parent or child id. - -Returns `IEnumerable`. - -{% hint style="info" %} -Using this method will get you all relations regards of it being a child or parent relation. -{% endhint %} - -### GetByRelationTypeAlias(string relationTypeAlias) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by their relation type alias. - -Returns `IEnumerable`. - -### GetByRelationTypeId(int relationTypeId) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by the id of their relation type. - -Returns `IEnumerable`. - -### GetByRelationTypeName(string relationTypeName) - -Gets a collection of `Umbraco.Core.Models.Relation` objects by the name of their relation type. - -Returns `IEnumerable`. - -### GetChildEntitiesFromRelations(IEnumerable relations) - -Gets the child objects from a collection of `IRelation` as a collection of `Umbraco.Core.Models.Entities.IUmbracoEntity`. - -Returns `IEnumerable`. - -### GetChildEntityFromRelation(IRelation relation) - -Gets the child object from a relation as an `Umbraco.Core.Models.Entities.IUmbracoEntity` object. - -Returns `IUmbracoEntity`. - -### GetEntitiesFromRelation(IRelation relation) - -Gets the parent and child objects from a relation as a `System.Tuple` with `Umbraco.Core.Models.Entities.IUmbracoEntity`. - -Returns `Tuple`. - -### GetEntitiesFromRelations(IEnumerable relations) - -Gets the parent and child objects from a collection of relations as a list of `Umbraco.Core.Models.Entities.IUmbracoEntity` objects. - -Returns `IEnumerable>`. - -### GetParentEntitiesFromRelations(IEnumerable relations) - -Gets the parent objects from a collection of relations as a collection of `Umbraco.Core.Models.Entities.IUmbracoEntity`. - -Returns `IEnumerable`. - -### GetParentEntityFromRelation(IRelation relation) - -Gets the parent object from a relation as an `Umbraco.Core.Models.Entities.IUmbracoEntity` object. - -### GetRelationTypeByAlias(string alias) - -Gets an relation by its alias. - -Returns `IRelationType`. - -### GetRelationTypeById(Guid id) - -Gets a relation type by its Id - -Returns `IRelationType`. - -### GetRelationTypeById(int id) - -Gets a relation type by its id. - -Returns `IRelationType`. - -### HasRelations(IRelationType relationType) - -Checks if any relations exist for the specified relation type. - -Returns `bool`. - -### IsRelated(int id) - -Checks if any relations exist for the specified id. - -Returns `void`. - -### Relate(int parentId, int childId, IRelationType relationType) - -Relates two objects by their ids using the specified relation type. - -Returns `IRelation`. - -### Relate(IUmbracoEntity parent, IUmbracoEntity child, IRelationType relationType) - -Relates two `IUmbracoEntity` objects using the specified relation type. - -Returns `IRelation`. - -### Relate(IUmbracoEntity parent, IUmbracoEntity child, string relationTypeAlias) - -Relates two `IUmbracoEntity` objects using the specified relation type alias. - -Returns `IRelation`. - -### Relate(int parentId, int childId, string relationTypeAlias) - -Relates two `IUmbracoEntity` objects using the specified relation type alias. - -Returns `IRelation`. - -### Save(IRelation relation) - -Saves a relation. - -Returns `Void`. - -### Save(IRelationType relationType) - -Saves a relation type. - -Returns `Void`. - -## Examples - -Below you will examples using the `RelationService`. - -### Automatically relate to root node - -Odd example, I know.. but why not? - -To perform the said task we need a component in which we can register to the `ContentService.Published` event: - -([You can read more about composing Umbraco here](../../../../implementation/composing/index.md)) - -```csharp -using System.Linq; -using Umbraco.Core.Composing; -using Umbraco.Core.Events; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; - -namespace Doccers.Core.Components -{ - public class RelationComponent : IComponent - { - private readonly IRelationService _relationService; - - public RelationComponent(IRelationService relationService) - { - _relationService = relationService; - } - - public void Initialize() - { - ContentService.Published += ContentService_Published; - } - - private void ContentService_Published(IContentService sender, - ContentPublishedEventArgs e) - { - // Should never be null, to be honest. - var home = sender.GetRootContent()?.FirstOrDefault(); - if (home == null) return; - - // Get the relation type by alias - var relationType = _relationService.GetRelationTypeByAlias("homesick"); - if (relationType == null) return; - - foreach (var entity in e.PublishedEntities - .Where(x => x.Id != home.Id)) - { - // Check if they are already related - if (!_relationService.AreRelated(home.Id, entity.Id)) - { - // If not then let us relate the current entity to home - _relationService.Relate(home.Id, entity.Id, relationType); - } - } - } - - public void Terminate() { - //unsubscribe during shutdown - ContentService.Published -= ContentService_Published; - } - } -} -``` - -To have Umbraco recognize our component we need to register it in a composer: - -```csharp -using Doccers.Core.Components; -using Umbraco.Core; -using Umbraco.Core.Composing; - -namespace Doccers.Core.Composers -{ - [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - public class RelationComposer : IUserComposer - { - public void Compose(Composition composition) - { - composition.Components().Append(); - } - } -} -``` - -If I know `Save and Publish` my `Products` node I get the following result: - -![Relations](images/relations.PNG) - -Cool! Now let us try and fetch the data from an API. - -```csharp -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Web.Http; -using Umbraco.Core.Services; -using Umbraco.Web.WebApi; - -namespace Doccers.Core.Controllers.Http -{ - public class RelationsController : UmbracoApiController - { - private readonly IRelationService _relationService; - - public RelationsController(IRelationService relationService) - { - // Alternatively you could also access - // the service via the service context: - // _relationService = Services.RelationService; - _relationService = relationService; - } - - [HttpGet] - public HttpResponseMessage GetByRelationTypeAlias(string alias) - { - var relationType = _relationService.GetRelationTypeByAlias(alias); - if (relationType == null) - return Request.CreateResponse(HttpStatusCode.BadRequest, - "Invalid relation type alias"); - - var relations = _relationService.GetAllRelationsByRelationType(relationType.Id); - var content = relations.Select(x => Umbraco.Content(x.ChildId)) - .Select(x => new Relation() - { - Name = x.Name, - UpdateDate = x.UpdateDate - }); - - return Request.CreateResponse(HttpStatusCode.OK, content); - } - } -} -``` - -Notice the `x => new Relation()`? We need to make sure what we are returning can be serialized. Therefore the `Relation` class is: - -```csharp -[DataContract(Name = "relation")] -public class Relation -{ - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "updateDate")] - public DateTime UpdateDate { get; set; } -} -``` - -Browsing `/umbraco/api/relations/getbyrelationtypealias?alias=homesick` now returns the following: - -![Relations](images/relations-api.PNG) - -{% hint style="info" %} -If you want to do something similar to this it is recommended that you wrap a caching layer around it, as the RelationService queries the database directly. -{% endhint %} diff --git a/10/umbraco-cms/reference/management/services/serverregistrationservice.md b/10/umbraco-cms/reference/management/services/serverregistrationservice.md deleted file mode 100644 index 2c2bb40d7c3..00000000000 --- a/10/umbraco-cms/reference/management/services/serverregistrationservice.md +++ /dev/null @@ -1,50 +0,0 @@ -# ServerRegistrationService - -The ServerRegistrationService manages server registrations in the database. - -[Browse the API documentation for IServerRegistrationService interface](https://apidocs.umbraco.com/v11/csharp/api/Umbraco.Cms.Core.Services.IServerRegistrationService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -The Umbraco.Core.dll allows you to reference the Constants classes used in the below examples. - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -For Razor views: - -```csharp -@using Umbraco.Cms.Core.Services -``` - -## Getting the service - -### Dependency Injection - -If you wish to use the server registration service in a class, you need to specify the IServerRegistrationService interface in your constructor: - -```csharp -public class MyClass -{ - private IServerRegistrationService _serverRegistrationService; - - public MyClass(IServerRegistrationService serverRegistrationService) - { - _serverRegistrationService = serverRegistrationService; - } -} -``` - -In Razor views, you can access the server registration service through the @inject directive: - -```csharp -@inject IServerRegistrationService ServerRegistrationService -``` diff --git a/10/umbraco-cms/reference/management/services/tagservice.md b/10/umbraco-cms/reference/management/services/tagservice.md deleted file mode 100644 index ea3b7585f24..00000000000 --- a/10/umbraco-cms/reference/management/services/tagservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# TagService - -Tag service to query for tags in the tags db table. - -[Browse the API documentation for ITagService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.ITagService.html). - -* **Namespace:** `Umbraco.Cms.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `ITagService` interface in your constructor: - -```csharp -public class MyClass -{ - private ITagService _tagService; - - public MyClass(ITagService tagService) - { - _tagService = tagService; - } -} -``` - -In Razor views, you can access the member service through the `@inject` directive: - -```csharp -@inject ITagService TagService -``` \ No newline at end of file diff --git a/10/umbraco-cms/reference/management/services/textservice.md b/10/umbraco-cms/reference/management/services/textservice.md deleted file mode 100644 index 7c6f2c37515..00000000000 --- a/10/umbraco-cms/reference/management/services/textservice.md +++ /dev/null @@ -1,42 +0,0 @@ -# TextService - -The TextService is the entry point to localize any key in the text storage source for a given culture. - -[Browse the API documentation for ILocalizedTextService interface](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Services.ILocalizedTextService.html). - - * **Namespace:** `Umbraco.Cms.Core.Services` - * **Assembly:** `Umbraco.Core.dll` - - All samples in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Cms.Core.Services; -``` - -## Getting the service - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `ILocalizedTextService` interface in your constructor: - -```csharp -public class MyClass -{ - private ILocalizedTextService _textService; - - public MyClass(ILocalizedTextService textService) - { - _textService = textService; - } -} -``` - -In Razor views, you can access the member service through the `@inject` directive: - -```csharp -@inject ILocalizedTextService LocalizedTextService -``` diff --git a/10/umbraco-cms/reference/management/services/userservice/README.md b/10/umbraco-cms/reference/management/services/userservice/README.md deleted file mode 100644 index dc4d5d31baf..00000000000 --- a/10/umbraco-cms/reference/management/services/userservice/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# UserService - -The UserService acts as a "gateway" to Umbraco data for operations which are related to Users. - -* **Namespace:** `Umbraco.Core.Services` -* **Assembly:** `Umbraco.Core.dll` - -All samples listed in this document will require references to the following dll: - -* Umbraco.Core.dll - -All samples in this document will require the following using statements: - -```csharp -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -``` - -## Getting the service - -### Services property - -If you wish to use the UserService in a class that inherits from one of the Umbraco base classes (eg. `SurfaceController`, `UmbracoApiController` or `UmbracoAuthorizedApiController`), you can access the service through a local `Services` property: - -```csharp -IUserService userService = Services.UserService; -``` - -### Dependency Injection - -In other cases, you may be able to use Dependency Injection. For instance if you have registered your own class in Umbraco's dependency injection, you can specify the `IUserService` interface in your constructor: - -```csharp -public class MyClass -{ - - private IUserService _userService; - - public MyClass(IUserService userService) - { - _userService = userService; - } - -} -``` - -### Static accessor - -If neither a `Services` property or Dependency Injection is available, you can also reference the static `Current` class directly: - -```csharp -IUserService userService = Umbraco.Core.Composing.Current.Services.UserService; -``` - -## Samples - -* [**Create a new user**](create-a-new-user.md)\ - Quick sample showing how to create a new backoffice user; including setting a password, assigning the user to a user group, and setting the name of the user. diff --git a/10/umbraco-cms/reference/management/services/userservice/create-a-new-user.md b/10/umbraco-cms/reference/management/services/userservice/create-a-new-user.md deleted file mode 100644 index 3ddd16e7b53..00000000000 --- a/10/umbraco-cms/reference/management/services/userservice/create-a-new-user.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: "This will show you how to create a new user using the UserService in Umbraco." ---- - -# Creating a user - -If you want to create a new user, you'd use ASP.NET identity APIs like it is used in core. - -### Assigning the user to a user group - -Permissions aren't administered for the specific user, but rather for the user group(s) that the user is a part of. So to add our new user to a user group, we first need to get a reference to the user via the `GetUserGroupByAlias` method, and then use the `AddGroup` method for adding the group to our user: - -```csharp -// Get a reference to the default "Administrators" user group -UserGroup adminUserGroup = (UserGroup) us.GetUserGroupByAlias("admin"); - -// Add the user to the user group -user.AddGroup(adminUserGroup); -``` - -To make sure that these changed are saved to the database, we must also make sure to call the `Save` method. The `GetUserGroupByAlias` method takes the alias of a user group - eg. `admin` for the default **Administrators** user group. diff --git a/10/umbraco-cms/reference/mapping.md b/10/umbraco-cms/reference/mapping.md deleted file mode 100644 index 3061f54065d..00000000000 --- a/10/umbraco-cms/reference/mapping.md +++ /dev/null @@ -1,305 +0,0 @@ ---- -meta.Title: UmbracoMapper ---- - -# UmbracoMapper - -Often in code there is a need to 'map' one object's properties to another type of object. The 'type of objects' are not related by inheritance or interface. (Think database layer object, passing information to a presentation layer ViewModel etc). In these circumstances, it can save time and provide consistency to consolidate the logic to map between the options into one set of 'Mapping' rules. - -{% hint style="info" %} -UmbracoMapper replaced AutoMapper which was an external dependency. AutoMapper builds the mapping code dynamically, based upon mapping profiles, which are defined as C# expressions. UmbracoMapper relies on static code, that is, mappings need to be hand-written. - -This is not to be confused with the [UmbracoMapper package by Andy Butland](https://our.umbraco.com/packages/developer-tools/umbraco-mapper) of the same name. -{% endhint %} - -UmbracoMapper was originally introduced to solve some issues in the Umbraco core code. However, it is fine for anyone to use in their custom site implementations or packages as they wish. - -## Accessing the IUmbracoMapper - -The IUmbracoMapper is registered with Dependency Injection (DI). It can therefore be injected into constructors of controllers, custom classes etc, wherever DI is used. - -## Mapping - -Mapping with the UmbracoMapper works in ways similar to AutoMapper: - -```csharp -// assuming source is ISource, create a new target instance -var target = umbracoMapper.Map(source); - -// assuming both source and target already exists -target = umbracoMapper.Map(source, target); -``` - -The UmbracoMapper class also defines explicit methods to map enumerables: - -```csharp -// assuming sources is IEnumerable, map to IEnumerable -var targets = umbracoMapper.MapEnumerable(sources); -``` - -Explicit mapping of enumerables enumerates the source items, and map each item individually. - -It can also implicitly map enumerables. The following code is also valid: - -```csharp -// assuming sources is IEnumerable, map to IEnumerable -var targets = umbracoMapper.Map>(sources); -``` - -If a mapping has been defined from `IEnumerable` to `IEnumerable`, then it will be used. Otherwise, the UmbracoMapper will look for a mapping from the source type to the target type, pretty much like the explicit method. - -## Defining mappings - -Mappings are defined in `IMapDefinition` instances. This interface defines one method: - -```csharp -void DefineMaps(IUmbracoMapper mapper); -``` - -Mappings are registered (and must be registered) via a [collection builder](../implementation/composing.md#collections): - -```csharp -builder.WithCollectionBuilder() - .Add(); -``` - -A definition provides a constructor, and a map: - -```csharp -public void DefineMaps(IUmbracoMapper mapper) -{ - mapper.Define( - (source, context) => { ... }, // constructor - (source, target, context) => { .... } // map - ); -} -``` - -The constructor function is used to create an instance of the target class. The most basic implementation would be: - -```csharp -(source, context) => new TargetClass(), -``` - -The mapping action is used to map an instance of the source class, to an instance of the target class. The most basic implementation would be: - -```csharp -(source, target, context) => -{ - target.MyProperty1 = source.MyProperty1; - target.MyProperty2 = source.MyProperty2; - ... -} -``` - -The constructor function is used whenever the mapper is asked to create a target instance. Then, the mapping action is used. - -In other words, `umbracoMapper.Map(source)` will first run the construction function, and then the mapping action. On the other hand, `umbracoMapper.Map(source, target)` where target already exists, would only run the mapping action. - -The UmbracoMapper class provides multiple overloads of the Define method: - -* An overload accepting a constructor function and a mapping action, as presented above. -* An overload accepting a mapping action only, which tells the mapper how to map to an existing target (but the mapper will not be able to create new target instances). -* An overload accepting a construction function, which tells the mapper how to create new target instances (but the mapper will not perform any additional mapping). -* A parameter-less overload, which defines a "no-operation" mapping (the mapper cannot create new target instance, and mapping does nothing). - -## Context - -Both constructor functions and map actions presented above expose a context parameter which is an instance of MapperContext and provides two types of services: - -* An `Items` dictionary which can store any type of object, using string keys, and can be used to carry some context along mappings; -* Some Map and MapEnumerable functions that can be used in mapping functions, to recursively map nested elements, while propagating the context. - -{% hint style="info" %} -The context provides a `HasItem` property. To check whether the context has items, without allocating an extra empty dictionary, use this property. -{% endhint %} - -The context is used, for instance, to carry the culture when mapping content items with variants. See the `MapperContextExtensions` class, which contains methods such as: - -```csharp -public static void SetCulture(this MapperContext context, string culture) -{ - context.Items[CultureKey] = culture; -} -``` - -And - -```csharp -public static string GetCulture(this MapperContext context) -{ - return context.HasItems && - context.Items.TryGetValue(CultureKey, out var obj) && - obj is string s - ? s - : null; -} -``` - -Every `Map` and `MapEnumerable` method exposed by the UmbracoMapper have overloads that can manipulate the context before executing the mapping. For instance, - -```csharp -var target = umbracoMapper.Map(source, context => - { - context.SetCulture(cultureName); - }); -``` - -## Umbraco.Code - -Umbraco.Code is an assembly which should contain coding utilities for Umbraco. At the moment, it contains only one Roslyn analyzer, the `MapAllAnalyzer`, which is used to help writing mapping methods. - -The code lives in the [Umbraco.Code repository](https://github.com/umbraco/Umbraco-Code) and the tool is available via [Nuget](https://www.nuget.org/packages/Umbraco.Code/). It is included as a development dependency in Umbraco. - -The analyzer examines every method mapping from a source to a target, and being marked with the `// Umbraco.Code.MapAll` comment block: - -```csharp -mapper.Define( - (source, context) => new Target(), // constructor - Map // map - ); - -// Umbraco.Code.MapAll -private static void Map(ISource source, - ITarget target, - MapperContext context) -{ - target.Property1 = source.Property1; - target.Property2 = source.Property2; -} -``` - -The analyzer verifies that every publicly settable property of target is assigned a value. If a property is not assigned a value, the tool raises a build error (ie. the code will not compile). - -Since, contrary to AutoMapper, mapping is not implicit nor automatic, this ensures that an error would be raised. Should a new property be added to ISource, the corresponding mappings must be updated. - -It is possible to exclude some properties from the check: - -```csharp -// Umbraco.Code.MapAll -Property2 -``` - -And the comment can be repeated if the list of excluded properties is long: - -```csharp -// Umbraco.Code.MapAll -Property2 -Property3 -Property4 -// Umbraco.Code.MapAll -Property5 -Property6 -Property7 -``` - -The analyzer follows the standard analyzer development patterns, and building the code in Release mode produces the appropriate NuGet package. - -## Full example - -Below you will find a full example showing you how to map a collection of type Product to a collection of type ProductDto. - -```csharp -#region Models - -public class Product -{ - public string Name { get; set; } - public string SuperSecretThingNotForPublicDisplay { get; set; } -} - -[DataContract(Name = "product")] -public class ProductDto -{ - [DataMember(Name = "name")] - public string Name { get; set; } -} - -#endregion - -#region Mapping - -public class ProductMappingDefinition : IMapDefinition -{ - public void DefineMaps(IUmbracoMapper mapper) - { - mapper.Define((source, context) => new ProductDto(), Map); - } - - private void Map(Product source, ProductDto target, MapperContext context) - { - target.Name = source.Name; - } -} - -#endregion - -#region Composing - -public class ProductComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.WithCollectionBuilder() - .Add(); - } -} - -#endregion - -public class ProductsController : UmbracoApiController -{ - private readonly IUmbracoMapper _mapper; - - public ProductsController(IUmbracoMapper mapper) => _mapper = mapper; - - [HttpGet] - public HttpResponseMessage GetAll() - { - var products = FakeServiceCall(); - var mapped = _mapper.MapEnumerable(products); - - return Request.CreateResponse(HttpStatusCode.OK, mapped); - } - - [HttpGet] - public HttpResponseMessage GetFirstProduct() - { - var product = FakeServiceCall().First(); - var mapped = _mapper.Map(product); - - return Request.CreateResponse(HttpStatusCode.OK, mapped); - } - - private IEnumerable FakeServiceCall() - { - return new List() - { - new Product() - { - Name = "Umbraco Cloud", - SuperSecretThingNotForPublicDisplay = "Secret" - }, - new Product() - { - Name = "Umbraco Forms", - SuperSecretThingNotForPublicDisplay = "Also secret" - } - }; - } -} -``` - -Result from `/umbraco/api/products/getall`: - -```json -[ - { - "name": "Umbraco Cloud" - }, - { - "name": "Umbraco Forms" - } -] -``` - -Result from `/umbraco/api/products/getfirstproduct`: - -```json -{ - "name": "Umbraco Cloud" -} -``` diff --git a/10/umbraco-cms/reference/notifications/README.md b/10/umbraco-cms/reference/notifications/README.md deleted file mode 100644 index 6579bc22e29..00000000000 --- a/10/umbraco-cms/reference/notifications/README.md +++ /dev/null @@ -1,318 +0,0 @@ ---- -description: Get started with Notifications. ---- - -# Using Notifications - -Umbraco uses Notifications (similar to the Observer pattern) to allow you to hook into the workflow process for the backoffice. For example, notifications allow you to execute some code every time a page is published. - -## Notifications - -All notifications reside in the `Umbraco.Cms.Core.Notifications` namespace and are postfixed with `Notification`. - -Available notifications typically exist in pairs, with "before" and "after" notifications. For example, the ContentService class has the concept of **publishing** and **published** notifications. So, there is both a `ContentPublishingNotification` and a `ContentPublishedNotification` notification. - -The notification to use depends on what you want to achieve. If you want to be able to cancel the action, you would use the `CancelOperation` method on the "before" notification. See the sample in [ContentService Notifications](contentservice-notifications.md). If you want to execute some code after the publishing has succeeded, then you would use the "after" notification. - -## Registering Notifications - -Check the [Notification Handler](notification-handler.md) article to learn more about notification handlers lifetime, async notification handler and how to register the notification handlers. - -## List of Notifications - -Below you can find a list of most used object notifications. - -You can find a list of all supported notifications in the [API Docs](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.html). - -### Content, Media, and Member notifications - -
- -ContentService Notifications - -The ContentService class is the most commonly used type when extending Umbraco using notifications. ContentService implements IContentService. It provides access to operations involving IContent. - -Below you can find a list of the most common ContentService object notifications. - -* [ContentSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentSavingNotification.html) -* [ContentSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentSavedNotification.html) -* [ContentPublishingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentPublishingNotification.html) -* [ContentPublishedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentPublishedNotification.html) -* [ContentUnpublishingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentUnpublishingNotification.html) -* [ContentUnpublishedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentUnpublishedNotification.html) -* [ContentCopyingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentCopyingNotification.html) -* [ContentCopiedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentCopiedNotification.html) -* [ContentMovingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentMovingNotification.html) -* [ContentMovedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentMovedNotification.html) -* [ContentMovingToRecycleBinNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentMovingToRecycleBinNotification.html) -* [ContentMovedToRecycleBinNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentMovedToRecycleBinNotification.html) -* [ContentDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentDeletingNotification.html) -* [ContentDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentDeletedNotification.html) -* [ContentDeletingVersionsNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentDeletingVersionsNotification.html) -* [ContentDeletedVersionsNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentDeletedVersionsNotification.html) -* [ContentRollingBackNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentRollingBackNotification.html) -* [ContentRolledBackNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentRolledBackNotification.html) -* [ContentSendingToPublishNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentSendingToPublishNotification.html) -* [ContentSentToPublishNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentSentToPublishNotification.html) -* [ContentEmptyingRecycleBinNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentEmptyingRecycleBinNotification.html) -* [ContentEmptiedRecycleBinNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentEmptiedRecycleBinNotification.html) -* [ContentSavedBlueprintNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentSavedBlueprintNotification.html) -* [ContentDeletedBlueprintNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentDeletedBlueprintNotification.html) - -
- -
- -MediaServiceNotifications - -Below you can find a list of the most common MediaService object notifications. - -* [MediaSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaSavingNotification.html) -* [MediaSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaSavedNotification.html) -* [MediaMovingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaMovingNotification.html) -* [MediaMovedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaMovedNotification.html) -* [MediaMovingToRecycleBinNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaMovingToRecycleBinNotification.html) -* [MediaMovedToRecycleBinNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaMovedToRecycleBinNotification.html) -* [MediaDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaDeletingNotification.html) -* [MediaDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaDeletedNotification.html) -* [MediaDeletingVersionsNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaDeletingVersionsNotification.html) -* [MediaDeletedVersionsNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaDeletedVersionsNotification.html) - -
- -
- -MemberService Notifications - -The MemberService implements IMemberService and provides access to operations involving IMember. - -Below you can find a list of the most common MemberService object notifications. - -* [MemberSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberSavingNotification.html) -* [MemberSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberSavedNotification.html) -* [MemberDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberDeletingNotification.html) -* [MemberDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberDeletedNotification.html) -* [AssignedMemberRolesNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.AssignedMemberRolesNotification.html) -* [RemovedMemberRolesNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RemovedMemberRolesNotification.html) - -
- -### Other notifications - -
- -ContentTypeService Notifications - -The ContentTypeService class implements IContentTypeService. It provides access to operations involving IContentType. - -Below you can find a list of the most common ContentTypeService object notifications. - -* [ContentTypeSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeSavingNotification.html) -* [ContentTypeSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeSavedNotification.html) -* [ContentTypeDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeDeletingNotification.html) -* [ContentTypeDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeDeletedNotification.html) -* [ContentTypeMovingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeMovingNotification.html) -* [ContentTypeMovedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeMovedNotification.html) -* [ContentTypeChangedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentTypeChangedNotification.html) - -
- -
- -MediaTypeService Notifications - object list - -The MediaTypeService class implements IMediaTypeService. It provides access to operations involving IMediaType. - -Below you can find a list of the most common MediaTypeService object notifications. - -* [MediaTypeSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeSavingNotification.html) -* [MediaTypeSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeSavedNotification.html) -* [MediaTypeDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeDeletingNotification.html) -* [MediaTypeDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeDeletedNotification.html) -* [MediaTypeMovingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeMovingNotification.html) -* [MediaTypeMovedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeMovedNotification.html) -* [MediaTypeChangedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaTypeChangedNotification.html) - -
- -
- -MemberTypeService Notifications - -The MemberTypeService class implements IMemberTypeService. It provides access to operations involving IMemberType - -Below you can find a list of the most common MemberTypeService object notifications. - -* [MemberTypeSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeSavingNotification.html) -* [MemberTypeSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeSavedNotification.html) -* [MemberTypeDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeDeletingNotification.html) -* [MemberTypeDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeDeletedNotification.html) -* [MemberTypeMovingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeMovingNotification.html) -* [MemberTypeMovedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeMovedNotification.html) -* [MemberTypeChangedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberTypeChangedNotification.html) - -
- -
- -DataTypeService Notifications - -The DataTypeService class implements IDataTypeService. It provides access to operations involving IDataType. - -Below you can find a list of the most common DataTypeService object notifications. - -* [DataTypeSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DataTypeSavingNotification.html) -* [DataTypeSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DataTypeSavedNotification.html) -* [DataTypeDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DataTypeDeletingNotification.html) -* [DataTypeDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DataTypeDeletedNotification.html) -* [DataTypeMovingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DataTypeMovingNotification.html) -* [DataTypeMovedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DataTypeMovedNotification.html) - -
- -
- -FileService Notifications - -The FileService class implements IFileService. It provides access to operations involving IFile objects like scripts, stylesheets and templates. - -Below you can find a list of the most common FileService object notifications. - -* [TemplateSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.TemplateSavingNotification.html) -* [TemplateSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.TemplateSavedNotification.html) -* [ScriptSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ScriptSavingNotification.html) -* [ScriptSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ScriptSavedNotification.html) -* [StylesheetSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.StylesheetSavingNotification.html) -* [StylesheetSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.StylesheetSavedNotification.html) -* [TemplateDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.TemplateDeletingNotification.html) -* [TemplateDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.TemplateDeletedNotification.html) -* [ScriptDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ScriptDeletingNotification.html) -* [ScriptDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ScriptDeletedNotification.html) -* [StylesheetDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.StylesheetDeletingNotification.html) -* [StylesheetDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.StylesheetDeletedNotification.html) - -
- -
- -LocalizationService Notifications - -The LocalizationService class implements ILocalizationService. It provides access to operations involving Language and DictionaryItem. - -Below you can find a list of the most common LocalizationService object notifications. - -* [LanguageSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.LanguageSavingNotification.html) -* [LanguageSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.LanguageSavedNotification.html) -* [DictionaryItemSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DictionaryItemSavingNotification.html) -* [DictionaryItemSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DictionaryItemSavedNotification.html) -* [LanguageDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.LanguageDeletingNotification.html) -* [LanguageDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.LanguageDeletedNotification.html) -* [DictionaryItemDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DictionaryItemDeletingNotification.html) -* [DictionaryItemDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.DictionaryItemDeletedNotification.html) - -
- -
- -CacheRefresher Notifications - -Below you can find a list of the most common CacheRefresher object notifications. - -* [ContentCacheRefresherNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.ContentCacheRefresherNotification.html) -* [MediaCacheRefresherNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MediaCacheRefresherNotification.html) -* [MemberCacheRefresherNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.MemberCacheRefresherNotification.html) -* [UserCacheRefresherNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.UserCacheRefresherNotification.html) - -
- -
- -RelationService Notifications - -Below you can find a list of the most common RelationService object notifications. - -The RelationService provides access to operations involving IRelation and IRelationType, and publishes the following relation notifications: - -* [RelationSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationSavingNotification.html) -* [RelationSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationSavedNotification.html) -* [RelationDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationDeletingNotification.html) -* [RelationDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationDeletedNotification.html) -* [RelationTypeSavingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationTypeSavingNotification.html) -* [RelationTypeSavedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationTypeSavedNotification.html) -* [RelationTypeDeletingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationTypeDeletingNotification.html) -* [RelationTypeDeletedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.RelationTypeDeletedNotification.html) - -
- -
- -UmbracoApplicationLifetime Notifications - -Represents an Umbraco application lifetime (starting, started, stopping, stopped) notification. - -Below you can find a list of the most common UmbracoApplicationLifetime object notifications. - -* [UmbracoApplicationStartingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.UmbracoApplicationStartingNotification.html) -* [UmbracoApplicationStartedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.UmbracoApplicationStartedNotification.html) -* [UmbracoApplicationStoppingNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.UmbracoApplicationStoppingNotification.html) -* [UmbracoApplicationStoppedNotification](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Notifications.UmbracoApplicationStoppedNotification.html) - -
- -### Tree notifications - -See [Tree Notifications](../../extending/section-trees/) for a list of the tree notifications. - -### Editor Model Notifications - -See [EditorModel Notifications](editormodel-notifications/) for a list of the EditorModel events. - -{% hint style="info" %} -Useful for manipulating the model before it is sent to an editor in the backoffice. It could be used to set a default value of a property on a new document. -{% endhint %} - -## Creating and publishing your own custom notifications - -Umbraco uses notifications to allow people to hook into different workflow processes. This notification pattern is extensible, allowing you to create and publish custom notifications, and other people to observe and hook into your custom processes. This approach can be useful when creating Umbraco packages. For more information on how you create and publish your own notifications, see the [creating and publishing notifications](creating-and-publishing-notifications.md) article. - -## Showing messages in the CMS - -When handling notifications for CMS actions, you can inform the Umbraco user of the status of your notification. This is done by adding to the `notification.Messages` property within the `Handle` function. - -This could be used to inform the user to an additional operation that has been performed, or alert them to an error that has occoured. - -For example, in a `ContentTypeSavedNotification`: - -``` -public void Handle(TemplateSavedNotification notification) -{ - bool success = DoAdditionalCode(); - - if (success) - { - //on success - notification.Messages.Add(new EventMessage("Save Successful", - "The content was saved successfully", - EventMessageType.Success)); - } - else - { - //on error - notification.Messages.Add(new EventMessage("An Error occoured", - "Detail about the error", - EventMessageType.Error)); - } -} -``` - -## Samples - -Below you can find some articles with some examples using Notifications. - -* [CacheRefresher Notification](cacherefresher-notifications.md) -* [ContentService Notifications](contentservice-notifications.md) -* [Determining if an entity is new](determining-new-entity.md) -* [MediaService Notifications](mediaservice-notifications.md) -* [MemberService Notifications](memberservice-notifications.md) -* [Sending Allowed Children Notification](sendingallowedchildrennotifications.md) -* [Umbraco Application Lifetime Notifications](umbracoapplicationlifetime-notifications.md) diff --git a/10/umbraco-cms/reference/notifications/cacherefresher-notifications.md b/10/umbraco-cms/reference/notifications/cacherefresher-notifications.md deleted file mode 100644 index 111b2493d2b..00000000000 --- a/10/umbraco-cms/reference/notifications/cacherefresher-notifications.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -description: Example of how to use a CacheRefresher Notification ---- - -# Cache Refresher Notifications - -Before starting with cache refresher notifications it's a good idea to ensure you need to use them. If you want to react to changes in content, for instance, there's no real reason to use these notifications. This is due to the [content service notifications](contentservice-notifications.md) being easier to work with. If you need to react to changes in the cache, then these are the notifications for you. - -Cache refresher notifications are sent when the cache has refreshed. There are multiple different types of cache refresher notifications. These types are based on what type has been updated in the cache, for instance, content or media. All these notifications inherit from the same base notification: `CacheRefresherNotification`. - -The base notification is implemented in the following way: - -```C# -public abstract class CacheRefresherNotification : INotification -{ - public CacheRefresherNotification(object messageObject, MessageType messageType) - { - MessageObject = messageObject ?? throw new ArgumentNullException(nameof(messageObject)); - MessageType = messageType; - } - - public object MessageObject { get; } - - public MessageType MessageType { get; } -} -``` - -As you can see this notification contains two properties, a `MessageObject` and a `MessageType`. The `MessageType` specifies what kind of cache operation was performed, for example `RemoveById`. The possible message types is as follows: - -```C# -public enum MessageType -{ - RefreshAll, - RefreshById, - RefreshByJson, - RemoveById, - RefreshByInstance, - RemoveByInstance, - RefreshByPayload, -} -``` - -The other parameter `MessageObject` will depend on what type of cache refresher notification you're handling. If you for instance handle the `ContentCacheNotification`, the message object will be `ContentCacheRefresher.JsonPayload[]`. - -This object contains the Id and key of the item being updated, as well as an enum specifying how the tree is updated: - -```C# -[Flags] -public enum TreeChangeTypes : byte -{ - None = 0, - - // all items have been refreshed - RefreshAll = 1, - - // an item node has been refreshed - // with only local impact - RefreshNode = 2, - - // an item node has been refreshed - // with branch impact - RefreshBranch = 4, - - // an item node has been removed - // never to return - Remove = 8, -} - -``` - -An example of working with the `ContentCacheNotification` can be seen here: - -```C# -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Services.Changes; - -namespace Umbraco.Cms.Web.UI; - -public class ContentCacheRefresherExample : INotificationHandler -{ - private readonly IContentService _contentService; - - public ContentCacheRefresherExample(IContentService contentService) - { - _contentService = contentService; - } - - public void Handle(ContentCacheRefresherNotification notification) - { - if (notification.MessageObject is not ContentCacheRefresher.JsonPayload[] payloads) - { - return; - } - - foreach (ContentCacheRefresher.JsonPayload payload in payloads) - { - if (payload.ChangeTypes is not TreeChangeTypes.RefreshNode or TreeChangeTypes.RefreshBranch) - { - return; - } - - // You can do stuff with the ID of the refreshed content, for instance getting it from the content service. - var refreshedContent = _contentService.GetById(payload.Id); - } - } -} - -``` diff --git a/10/umbraco-cms/reference/notifications/contentservice-notifications.md b/10/umbraco-cms/reference/notifications/contentservice-notifications.md deleted file mode 100644 index 11b45d27b0e..00000000000 --- a/10/umbraco-cms/reference/notifications/contentservice-notifications.md +++ /dev/null @@ -1,229 +0,0 @@ ---- -description: >- - Find out more about ContentService Notifications and explore some example of - how to use it ---- - -# ContentService Notifications Example - -The ContentService class is the most commonly used type when extending Umbraco using notifications. ContentService implements IContentService. It provides access to operations involving IContent. - -## Usage - -Example usage of the ContentPublishingNotification: - -```csharp -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class DontShout : INotificationHandler - { - public void Handle(ContentPublishingNotification notification) - { - foreach (var node in notification.PublishedEntities) - { - if (node.ContentType.Alias.Equals("announcement")) - { - var newsArticleTitle = node.GetValue("title"); - if (newsArticleTitle.Equals(newsArticleTitle.ToUpper())) - { - notification.CancelOperation(new EventMessage("Corporate style guideline infringement", - "Don't put the announcement title in upper case, no need to shout!", - EventMessageType.Error)); - } - } - } - } - } -} -``` - -The handler will also need to be registered. See the [Notifications article](https://docs.umbraco.com/umbraco-cms/reference/notifications#registering-notification-handlers) for specifics on how to do this. - -### Variants and Notifications - -Umbraco V8 introduced the concept of Variants for Document Types, initially to allow different language variants of particular properties within a Document Type to be edited/translated based on the languages configured in your instance of Umbraco. - -These variants can be saved, published, and unpublished independently of each other. (Unpublishing a 'mandatory language' variant of a content item - will trigger all culture variants to be unpublished). - -This poses a problem when handling notifications from the ContentService - eg which culture got published? Do I want to run my 'custom' code that fires on save if it's only the Spanish version that's been published? Also, if only the Spanish variant is 'unpublished' - that feels like a different situation than if 'all the variants' have been 'unpublished'. Depending on which event you are handling there are helper methods you can call to find out. - -#### Saving - -When handling the ContentSavingNotification which will be published whenever a variant is saved. You can tell 'which' variant has triggered the save using an extension method on the ContentSavingNotification called 'IsSavingCulture' - -```csharp -public bool IsSavingCulture(IContent content, string culture); -``` - -As an example, you could check which cultures are being saved (it could be multiple if multiple checkboxes are checked) - -```csharp -public void Handle(ContentSavingNotification notification) -{ - foreach (var entity in notification.SavedEntities) - { - // Cultures being saved - var savingCultures = entity.AvailableCultures - .Where(culture => notification.IsSavingCulture(entity, culture)).ToList(); - // or - if (notification.IsSavingCulture(entity, "en-GB")) - { - // Do things differently if the UK version of the page is being saved. - } - } -} -``` - -#### Saved - -With the Saved notification you can similarly use the 'HasSavedCulture' method of the 'ContentSavedNotification' to detect which culture caused the Save. - -```csharp -public bool HasSavedCulture(IContent content, string culture); -``` - -#### Unpublishing - -When handling the Unpublishing notification, it might not work how you would expect. If 'all the variants' are being unpublished at the same time (or the mandatory language is being unpublished, which forces this to occur) then the Unpublishing notification will be published as expected. - -```csharp -public void Handle(ContentUnpublishingNotification notification) -{ - foreach (var unPublishedEntity in notification.UnpublishedEntities) - { - // complete unpublishing of entity, all cultures - } -} -``` - -However, if only one variant is being unpublished, the Unpublishing event will not be triggered. This is because the content item itself is not fully 'unpublished' by the action. Instead, what occurs is a 'publish' action 'without' the unpublished variant. - -You can therefore detect the Unpublishing of a variant in the publishing notification - using the IsUnpublishingCulture extension method of the `ContentPublishingNotification` - -```csharp -public void Handle(ContentPublishingNotification notification) -{ - foreach (var node in notification.PublishedEntities) - { - if (notification.IsUnpublishingCulture(node, "da-DK")) - { - // Bye bye DK! - } - } -} -``` - -#### Unpublished - -Again, the Unpublished notification does not get published when a single variant is Unpublished, instead, the Published notification can be used, and the 'HasUnpublishedCulture' extension method of the ContentPublishedNotification can determine which variant being unpublished triggered the publish. - -```csharp -public bool HasUnpublishedCulture(IContent content, string culture); -``` - -#### Publishing - -When handling the ContentPublishingNotification which will be triggered whenever a variant is published (or unpublished - see note in the Unpublishing section above). - -You can tell 'which' variant has triggered the publish using a helper method on the ContentPublishingNotification called IsPublishingCulture. - -```csharp -public bool IsPublishingCulture(IContent content, string culture); -``` - -For example, you could check which cultures are being published and act accordingly (it could be multiple if multiple checkboxes are checked). - -```csharp -public void Handle(ContentPublishingNotification notification) -{ - foreach (var node in notification.PublishedEntities) - { - var publishingCultures = node.AvailableCultures - .Where(culture => notification.IsPublishingCulture(node, culture)).ToList(); - - var unPublishingCultures = node.AvailableCultures - .Where(culture => notification.IsUnpublishingCulture(node, culture)).ToList(); - // or - if (notification.IsPublishingCulture(node, "da-DK")) - { - // Welcome back DK! - } - } -} -``` - -#### Published - -In the Published notification you can similarly use the HasPublishedCulture and HasUnpublishedCulture methods of the 'ContentPublishedEventArgs' to detect which culture caused the Publish or the UnPublish if it was only a single non-mandatory variant that was unpublished. - -```csharp -public bool HasPublishedCulture(IContent content, string culture); -public bool HasUnpublishedCulture(IContent content, string culture); -``` - -#### IContent Helpers - -In each of these notifications, the entities being Saved, Published, and Unpublished are `IContent` entities. There are some useful helper methods on IContent to discover the status of the content item's variant cultures: - -```csharp -bool IsCultureAvailable(string culture); -bool IsCultureEdited(string culture); -bool IsCulturePublished(string culture); -``` - -
- -What happened to Creating and Created events? - -Both the ContentService.Creating and ContentService.Created events were removed, and therefore never moved to notifications. Why? Because these events were not guaranteed to trigger and therefore should not be used. This is because these events would only trigger when the ContentService.CreateContent method was used which is an entirely optional way to create content entities. It is also possible to construct a new content item - which is generally the preferred and consistent way - and therefore the Creating/Created events would not execute when constructing content that way. - -Furthermore, there was no reason to listen to the Creating/Created events. They were misleading since they didn't trigger before and after the entity persisted. They are triggered inside the CreateContent method which never persists the entity, it constructs a new content object. - -**What do we use instead?** - -The ContentSavingNotification and ContentSavedNotification will always be published before and after an entity has been persisted. You can determine if an entity is brand new in either of those notifications. In the Saving notification - before the entity is persisted - you can check the entity's HasIdentity property which will be 'false' if it is brand new. In the Saved notification you can [check to see if the entity 'remembers being dirty'](determining-new-entity.md) - -
- -
- -What happened to raiseEventmethod parameters? - -RaiseEvent method service parameters have been removed from v9 and to name some reasons why: - -* Because it's entirely inconsistent, not all services have this as method parameters and maintaining that consistency is impossible especially if 3rd party libraries support events/notifications. -* It's hacky. There's no good way to suppress events/notifications this way at a higher (scoped) level. -* There's also hard-coded logic to ignore these parameters sometimes which makes it even more inconsistent. -* There are events below services at the repository level that cannot be controlled by this flag. - -**What do we use instead?** - -We can suppress notifications at the scope level which makes things consistent and will work for all services that use a Scope. Also, there's no required maintenance to make sure that new service methods will also work. - -**How to use scopes**: - -* Create an explicit scope and call scope.Notifications.Suppress(). -* The result of Suppress() is IDisposable, so until it is disposed, notifications will not be added to the queue. - -[Example](https://github.com/umbraco/Umbraco-CMS/blob/b69afe81f3f6fcd37480b3b0295a62af44ede245/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs#L35): - -```csharp -using (IScope scope = ScopeProvider.CreateScope(autoComplete: true)) -using (IDisposable _ = scope.Notifications.Suppress()) -{ - // TODO: Calls to service methods here will not have notifications -} -``` - -Child scope will inherit the parent Scope's notification object which means if a parent scope has notifications suppressed, then so does the child scope. You cannot call Suppress() more than once for the same outer scope instance else an exception will be thrown. This ensures that you cannot un-suppress notifications at a child level for an outer scope. It also ensures that suppressing events is an explicit thing to do. - -**Why would one want to suppress events?** - -The main reason for ever doing this would be performance for bulk operations. The callers should be aware that suppressing events will lead to an inconsistent content cache state (if notifications are suppressed for content or media services). This is because notifications are used by NuCache to populate the cmsContentNu table and populate the content caches. They are also used to populate the Examine indexes. - -So if you did suppress events, it will require you to rebuild the NuCache and examine data manually. - -
diff --git a/10/umbraco-cms/reference/notifications/creating-and-publishing-notifications.md b/10/umbraco-cms/reference/notifications/creating-and-publishing-notifications.md deleted file mode 100644 index ad44a4c1e3d..00000000000 --- a/10/umbraco-cms/reference/notifications/creating-and-publishing-notifications.md +++ /dev/null @@ -1,217 +0,0 @@ ---- - -meta-title: Creating and Publishing Custom Notifications -description: How to create and publish your own custom notifications ---- - -# Creating And Publishing Custom Notifications - -There may be many reasons why you would like to create your own custom notifications, in this article we'll use the CleanUpYourRoom [recurring hosted service](../scheduling.md) as an example, which empties the recycle bin every 5 minutes. You might want to publish a notification once the task has started, and maybe once the task has successfully cleared the recycle bin. - -For a notification to be publishable there's only one requirement, it must implement the empty marker interface `INotification`, the rest is up to you. For instance, we might want to create a notification that just signals that the clean your room task has started and nothing else, in this case, we'll create an empty class implementing `INotification` - -{% tabs %} -{% tab title="Latest version" %} -```C# -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Cms.Web.UI.Notifications -{ - public class CleanYourRoomStartedNotification : INotification - { - - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```C# -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class CleanYourRoomStartedNotification : INotification - { - - } -} -``` -{% endtab %} -{% endtabs %} - -This notification can now be published, and we can create a notification handler to receive it with, see [MediaService-Notifications](mediaservice-notifications.md) for an example of how to implement a notification handler. But this notification alone might not be super helpful, we might want to be able to send some additional information with the notification, however, since this is, in essence, just a normal class, we can include whatever information we want. Let's try and create a `RoomCleanedNotification` which contains the number of nodes removed from the recycle bin: - -{% tabs %} -{% tab title="Latest version" %} -```C# -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Cms.Web.UI.Notifications -{ - public class RoomCleanedNotification : INotification - { - public int ItemsDeleted { get; } - - public RoomCleanedNotification(int itemsDeleted) - { - ItemsDeleted = itemsDeleted; - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```C# -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class RoomCleanedNotification : INotification - { - public int ItemsDeleted { get; } - - public RoomCleanedNotification(int itemsDeleted) - { - ItemsDeleted = itemsDeleted; - } - } -} -``` -{% endtab %} -{% endtabs %} - -Now you can create a handler that receives the amount of items deleted through the notification. - -# Sending notifications - -Just creating the notification classes is not enough, we also want to be able to publish them. There's two ways of publishing notifications: - -* `IEventAggregator` - Notifications published with `IEventAggregator` will always be published immediately. -* `IScope.Notifications` - Notifications published with a scope will only be published once the scope has been completed and disposed. - -The method you use to publish notifications depends on what your needs are, the benefits of publishing notifications with a scope is that the notification will only be published if you complete the scope, and then only once the scope is disposed of. This can be useful if you access the database, or do some other operation that might fail causing you to do a rollback, disposing of the scope without completing it, in this case, you might not want to publish a notification that signals that the operation was a success, using scopes will handle this for you. On the other hand, you might want to publish the notification immediately no matter what, for instance with the `CleanYourRoomStartedNotification`, for this, the `IEventAggregator` is the right choice. - -## Example - -{% tabs %} -{% tab title="Latest version" %} -```C# -using System; -using System.Threading.Tasks; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Cms.Web.UI.Notifications; - -namespace Umbraco.Cms.Web.UI -{ - public class CleanUpYourRoom : RecurringHostedServiceBase - { - private readonly IContentService _contentService; - private readonly ICoreScopeProvider _coreScopeProvider; - private readonly IEventAggregator _eventAggregator; - private static TimeSpan HowOftenWeRepeat => TimeSpan.FromMinutes(5); - private static TimeSpan DelayBeforeWeStart => TimeSpan.FromMinutes(1); - - public CleanUpYourRoom( - IContentService contentService, - ICoreScopeProvider coreScopeProvider, - IEventAggregator eventAggregator, - ILogger logger) - : base(logger, HowOftenWeRepeat, DelayBeforeWeStart) - { - _contentService = contentService; - _coreScopeProvider = coreScopeProvider; - _eventAggregator = eventAggregator; - } - - public override Task PerformExecuteAsync(object state) - { - // This will be published immediately - _eventAggregator.Publish(new CleanYourRoomStartedNotification()); - - using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); - int numberOfThingsInBin = _contentService.CountChildren(Constants.System.RecycleBinContent); - - if (_contentService.RecycleBinSmells()) - { - _contentService.EmptyRecycleBin(userId: -1); - // This will only be published when the scope is completed and disposed. - scope.Notifications.Publish(new RoomCleanedNotification(numberOfThingsInBin)); - } - - // Remember to complete the scope when done. - scope.Complete(); - return Task.CompletedTask; - } - } -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```C# -using System; -using System.Threading.Tasks; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Cms.Web.UI.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class CleanUpYourRoom : RecurringHostedServiceBase - { - private readonly IContentService _contentService; - private readonly IScopeProvider _scopeProvider; - private readonly IEventAggregator _eventAggregator; - private static TimeSpan HowOftenWeRepeat => TimeSpan.FromMinutes(5); - private static TimeSpan DelayBeforeWeStart => TimeSpan.FromMinutes(1); - - public CleanUpYourRoom( - IContentService contentService, - IScopeProvider scopeProvider, - IEventAggregator eventAggregator) - : base(HowOftenWeRepeat, DelayBeforeWeStart) - { - _contentService = contentService; - _scopeProvider = scopeProvider; - _eventAggregator = eventAggregator; - } - - public override Task PerformExecuteAsync(object state) - { - // This will be published immediately - _eventAggregator.Publish(new CleanYourRoomStartedNotification()); - - using IScope scope = _scopeProvider.CreateScope(); - - int numberOfThingsInBin = _contentService.CountChildren(Constants.System.RecycleBinContent); - - if (_contentService.RecycleBinSmells()) - { - _contentService.EmptyRecycleBin(userId: -1); - - // This will only be published when the scope is completed and disposed. - scope.Notifications.Publish(new RoomCleanedNotification(numberOfThingsInBin)); - } - - // Remember to complete the scope when done. - scope.Complete(); - - return Task.CompletedTask; - } - } -} -``` -{% endtab %} -{% endtabs %} - -In this case, the `CleanYourRoomStartedNotification` will always be published immediately, however, `RoomCleanedNotification` will only be published once the operation is done, and if you remove the `scope.Complete();` line it will never be published, the recycle bin won't be emptied either. - diff --git a/10/umbraco-cms/reference/notifications/determining-new-entity.md b/10/umbraco-cms/reference/notifications/determining-new-entity.md deleted file mode 100644 index ce1f03bbaa2..00000000000 --- a/10/umbraco-cms/reference/notifications/determining-new-entity.md +++ /dev/null @@ -1,31 +0,0 @@ ---- - - ---- - -# Determining if an entity is new - -Many of the Umbraco services publishes a 'Saved' notification (or similar). In some cases, it is beneficial to know if this entity is a brand new entity that has been persisted in the database. This is how you can determine this. - -## Checking if it's new - -We know that if an entity is new and hasn't been persisted that it will not have an ID. Therefore we know if an entity has been newly persisted to the database by checking if its ID was changed before being persisted. - -Here's the snippet of code that does that: - -```C# -var dirty = (IRememberBeingDirty)entity; -var isNew = dirty.WasPropertyDirty("Id"); -``` - -To check if an entity is new in the ContentSavingNotification use the following: - -```C# -var isNew = entity.HasIdentity is false; -``` - -Since the IContent has not been saved yet, it's not necessary to cast it to `IRememberBeingDirty`. It won't have an identity if it's new, since it hasn't been committed yet. - -## How it works - -This is all possible because of the `IRememberBeingDirty` interface. Indeed the name of this interface is hilarious but it describes exactly what it does. All entities implement this interface which is really handy. It tracks not only the property data that has changed because it inherits from yet another hilarious interface called `ICanBeDirty`. It also tracks the property data that was changed before it was committed. \ No newline at end of file diff --git a/10/umbraco-cms/reference/notifications/editormodel-notifications/README.md b/10/umbraco-cms/reference/notifications/editormodel-notifications/README.md deleted file mode 100644 index 53e998f4a0d..00000000000 --- a/10/umbraco-cms/reference/notifications/editormodel-notifications/README.md +++ /dev/null @@ -1,249 +0,0 @@ ---- - - ---- - -# EditorModel Notifications - -EditorModel notifications enable you to manipulate the model used by the backoffice before it is loaded into an editor. For example the `SendingContentNotification` is published right before a content item is loaded into the backoffice for editing. It is therefore the perfect notification to use to set a default value for a particular property, or perhaps to hide a property/tab/Content App from a certain editor. - -## Usage - -Example usage of the `SendingContentNotification` - e.g. set the default PublishDate for a new NewsArticle to be today's Date: - -```C# -using System; -using System.Linq; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Models.ContentEditing; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Extensions; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class EditorSendingContentNotificationHandler : INotificationHandler - { - public void Handle(SendingContentNotification notification) - { - if (notification.Content.ContentTypeAlias.Equals("blogpost")) - { - // Access the property you want to pre-populate - // each content item can have 'variations' - each variation is represented by the `ContentVariantDisplay` class. - // if your site uses variants, then you need to decide whether to set the default value for all variants or a specific variant - // eg. set by variant name: - // var variant = notification.Content.Variants.FirstOrDefault(f => f.Name == "specificVariantName"); - // OR loop through all the variants: - foreach (var variant in notification.Content.Variants) - { - // Check if variant is a 'new variant' - // we only want to set the default value when the content item is first created - if (variant.State == ContentSavedState.NotCreated) - { - // each variant has an IEnumerable of 'Tabs' (property groupings) - // and each of these contain an IEnumerable of `ContentPropertyDisplay` properties - // find the first property with alias 'publishDate' - var pubDateProperty = variant.Tabs.SelectMany(f => f.Properties) - .FirstOrDefault(f => f.Alias.InvariantEquals("publishDate")); - if (pubDateProperty is not null) - { - // set default value of the publish date property if it exists - pubDateProperty.Value = DateTime.UtcNow; - } - } - } - } - } - } -} -``` - -Another example could be to set the default Member Group for a specific Member Type using `SendingMemberNotification`: - -```C# -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Services; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class EditorSendingMemberNotificationHandler : INotificationHandler - { - private readonly IMemberGroupService _memberGroupService; - - public EditorSendingMemberNotificationHandler(IMemberGroupService memberGroupService) - { - _memberGroupService = memberGroupService; - } - - public void Handle(SendingMemberNotification notification) - { - var isNew = !int.TryParse(notification.Member.Id?.ToString(), out int id) || id == 0; - - // We only want to set the default member group when the member is initially created, eg doesn't have an Id yet - if (isNew is false) - { - return; - } - - // Set a default value member group for the member type `Member` - if (notification.Member.ContentTypeAlias.Equals("Member")) - { - var memberGroup = _memberGroupService.GetByName("Customer"); - if (memberGroup is null) - { - return; - } - - // Find member group property on member model - var property = notification.Member.MembershipProperties.FirstOrDefault(x => - x.Alias.Equals($"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}membergroup")); - - if (property is not null) - { - // Assign a default value for member group property - property.Value = new Dictionary - { - {memberGroup.Name, true} - }; - } - } - } - } -} -``` - -## Notifications - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NotificationMembersDescription
SendingContentNotification -
    -
  • ContentItemDisplay Content
  • -
  • IUmbracoContext UmbracoContext
  • -
-
- Published right before the editor model is sent for editing in the content section.
- NOTE: Content is a Umbraco.Cms.Core.Models.ContentEditing.ContentItemDisplay type which contains the tabs and properties of the elements about to be loaded for editing. -
SendingMediaNotification -
    -
  • MediaItemDisplay Media
  • -
  • IUmbracoContext UmbracoContext
  • -
-
Published right before the editor model is sent for editing in the media section
- NOTE: Media is a Umbraco.Cms.Core.Models.ContentEditing.MediaItemDisplay type which in turn contains the tabs and properties of the elements about to be loaded for editing. -
SendingMemberNotification -
    -
  • MemberDisplay Member
  • -
  • IUmbracoContext UmbracoContext
  • -
-
- Published right before the editor model is sent for editing in the member section.
- NOTE: Member is a Umbraco.Cms.Core.Models.ContentEditing.MemberDisplay type which in turn contains the tabs and properties of the elements about to be loaded for editing. -
SendingUserNotification -
    -
  • UserDisplay User
  • -
  • IUmbracoContext UmbracoContext
  • -
-
- Published right before the editor model is sent for editing in the user section.
- NOTE: User is a Umbraco.Cms.Core.Models.ContentEditing.UserDisplay type which in turn contains the tabs and properties of the elements about to be loaded for editing. -
SendingDashboardsNotification -
    -
  • IEnumerable<Tab<IDashboardSlim>> Dashboards
  • -
  • IUmbracoContext UmbracoContext
  • -
-
- Published right before the a dashboard is retrieved in a section.
- NOTE: Dashboards is a collection of IDashboardSlim, each object gives you access to Label, Alias, Properties, whether it's expanded, and whether it IsActive. -
SendingAllowedChildrenNotification -
    -
  • IEnumerable<ContentTypeBasic> Children
  • -
  • IUmbracoContext UmbracoContext
  • -
-
- Published right before the allowed children of the selected Content Type are sent back during content creation in the Content Section.
- NOTE: Children is a collection of ContentTypeBasic, each object gives you access to Alias, Description, Thumbnail and more. You can remove or add new children to the list in the notification. -
- -### Display models - -#### ContentItemDisplay - -A model representing a content item to be displayed in the backoffice - -* TemplateAlias -* Urls -* AllowPreview - Determines whether previewing is allowed for this node, By default this is true but by using notifications developers can toggle this off for certain documents if there is nothing to preview -* AllowedActions - The allowed 'actions' based on the user's permissions - Create, Update, Publish, Send to publish -* IsBlueprint -* Tabs - Defines the tabs containing display properties -* Properties - properties based on the properties in the tabs collection -* And more... - -#### MediaItemDisplay - -A model representing a media item to be displayed in the backoffice - -* Alias -* Tabs - Defines the tabs containing display properties -* Properties - properties based on the properties in the tabs collection -* And more... - -#### MemberDisplay - -A model representing a member to be displayed in the backoffice - -* Username -* Email -* Tabs - Defines the tabs containing display properties -* Properties - properties based on the properties in the tabs collection -* And more... - -## Samples - -The EditorModel notifications gives you a lot of options to customize the backoffice experience. You can find inspiration from the various samples provided below: - -* [Customizing the "Links" box](customizing-the-links-box.md) diff --git a/10/umbraco-cms/reference/notifications/editormodel-notifications/customizing-the-links-box.md b/10/umbraco-cms/reference/notifications/editormodel-notifications/customizing-the-links-box.md deleted file mode 100644 index e330db63d76..00000000000 --- a/10/umbraco-cms/reference/notifications/editormodel-notifications/customizing-the-links-box.md +++ /dev/null @@ -1,26 +0,0 @@ -# Customizing the "Links" box - -For a content item, Umbraco will show a **Links** box within the **Info** content app. By default, this box will show one or more links to content item. - -![image](images/properties-info-app.png) - -With the `SendingContentNotification` event, we can manipulate the links in the `Urls` property. This could be by replacing it with custom links although a URL provider would be more suitable: - -```C# -public void Handle(SendingContentNotification notification) -{ - notification.Content.Urls = new[] - { - new UrlInfo($"/products/?id={notification.Content.Id}", true, CultureInfo.CurrentCulture.Name) - }; -} -``` - -or remove the box entirely by providing an empty list of links: - -```C# -public void Handle(SendingContentNotification notification) -{ - notification.Content.Urls = null; -} -``` diff --git a/10/umbraco-cms/reference/notifications/editormodel-notifications/images/properties-info-app.png b/10/umbraco-cms/reference/notifications/editormodel-notifications/images/properties-info-app.png deleted file mode 100644 index 3af83b41b26..00000000000 Binary files a/10/umbraco-cms/reference/notifications/editormodel-notifications/images/properties-info-app.png and /dev/null differ diff --git a/10/umbraco-cms/reference/notifications/mediaservice-notifications.md b/10/umbraco-cms/reference/notifications/mediaservice-notifications.md deleted file mode 100644 index 91624753816..00000000000 --- a/10/umbraco-cms/reference/notifications/mediaservice-notifications.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -description: Example of how to use a MediaService Notification ---- - -# MediaService Notifications Example - -The MediaService class implements IMediaService. It provides access to operations involving IMedia. - -## Usage - -Example usage of the MediaService notifications: - -```csharp -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace MySite -{ - public class MediaNotificationHandler : INotificationHandler - { - private readonly ILogger _logger; - - public MediaNotificationHandler(ILogger logger) - { - _logger = logger; - } - - public void Handle(MediaSavedNotification notification) - { - foreach (var mediaItem in notification.SavedEntities) - { - if (mediaItem.ContentType.Alias.Equals("Image")) - { - // Do something with the image, maybe send to Azure for AI analysis of image contents or something. - _logger.LogDebug($"Sending {mediaItem.Name} to analysis"); - SendToAzure(mediaItem); - } - } - } - } -} -``` - -## Returning messages to the user - -You can return a custom message to the user. Use this to show information, a warning or maybe an error. This is achieved using the `Messages` property of the notification and a composer. - -### Example - -This example returns an informational message to the user when a Media item is saved. - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace MyProject -{ - public class CustomComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } - } - - public class MediaNotificationTest : INotificationHandler - { - public void Handle(MediaSavedNotification notification) - { - notification.Messages.Add(new EventMessage( - "Notification", - "You can return a message to the user, using the messages property on the notification.", - EventMessageType.Info)); - } - } -} -``` - -![image](https://github.com/umbraco/UmbracoDocs/assets/6904597/67696298-2710-4aeb-bd0a-33c6d8414216) - -
- -What happened to Creating and Created events? - -Both the MediaService.Creating and MediaService.Created events have been obsoleted. Because of this, these were not moved over to notifications, and no longer exist. Why? Because these events were not guaranteed to trigger and therefore should not have been used. This is because these events _only_ triggered when the MediaService.CreateMedia method was used which is an entirely optional way to create media entities. It is also possible to construct a new media item - which is generally the preferred and consistent way - and therefore the Creating/Created events would not execute when constructing media that way. - -Furthermore, there was no reason to listen for the Creating/Created events because they were misleading. They didn't trigger before and after the entity had been persisted. Instead they triggered inside the CreateMedia method which never persists the entity. It constructs a new media object. - -**What do we use instead?** - -The MediaSavingNotification and MediaSavedNotification will always be published before and after an entity has been persisted. You can determine if an entity is brand new with either of those notifications. With the Saving notification - before the entity is persisted - you can check the entity's HasIdentity property which will be 'false' if it is brand new. In the Saved event you can [check to see if the entity 'remembers being dirty'](determining-new-entity.md) - -
- -
- -What happened to raiseEventmethod parameters? - -RaiseEvent method service parameters have been removed from v9 and to name some reasons why: - -* Because it's entirely inconsistent, not all services have this as method parameters and maintaining that consistency is impossible especially if 3rd party libraries support events/notifications. -* It's hacky. There's no good way to suppress events/notifications this way at a higher (scoped) level. -* There's also hard-coded logic to ignore these parameters sometimes which makes it even more inconsistent. -* There are events below services at the repository level that cannot be controlled by this flag. - -**What do we use instead?** - -We can suppress notifications at the scope level which makes things consistent and will work for all services that use a Scope. Also, there's no required maintenance to make sure that new service methods will also work. - -**How to use scopes**: - -* Create an explicit scope and call scope.Notifications.Suppress(). -* The result of Suppress() is IDisposable, so until it is disposed, notifications will not be added to the queue. - -[Example](https://github.com/umbraco/Umbraco-CMS/blob/b69afe81f3f6fcd37480b3b0295a62af44ede245/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs#L35): - -```csharp -using (IScope scope = ScopeProvider.CreateScope(autoComplete: true)) -using (IDisposable _ = scope.Notifications.Suppress()) -{ - // TODO: Calls to service methods here will not have notifications -} -``` - -Child scope will inherit the parent Scope's notification object which means if a parent scope has notifications suppressed, then so does the child scope. You cannot call Suppress() more than once for the same outer scope instance else an exception will be thrown. This ensures that you cannot un-suppress notifications at a child level for an outer scope. It also ensures that suppressing events is an explicit thing to do. - -**Why would one want to suppress events?** - -The main reason for ever doing this would be performance for bulk operations. The callers should be aware that suppressing events will lead to an inconsistent content cache state (if notifications are suppressed for content or media services). This is because notifications are used by NuCache to populate the cmsContentNu table and populate the content caches. They are also used to populate the Examine indexes. - -So if you did suppress events, it will require you to rebuild the NuCache and examine data manually. - -
diff --git a/10/umbraco-cms/reference/notifications/memberservice-notifications.md b/10/umbraco-cms/reference/notifications/memberservice-notifications.md deleted file mode 100644 index 29bbf40c02a..00000000000 --- a/10/umbraco-cms/reference/notifications/memberservice-notifications.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -description: Example of how to use a MemberService Notification ---- - -# MemberService Notifications Example - -The MemberService implements IMemberService and provides access to operations involving IMember. - -## Usage - -```csharp -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Services.Notifications; - -namespace MySite -{ - public class MemberNotificationHandler : INotificationHandler - { - private readonly ILogger _logger; - - public MemberNotificationHandler(ILogger logger) - { - _logger = logger; - } - - public void Handle(MemberSavedNotification notification) - { - foreach (var member in notification.SavedEntities) - { - // Write to the logs every time a member is saved. - _logger.LogInformation("Member {member} has been saved and notification published!", member.Name); - } - } - } -} -``` - -
- -What happened to raiseEventmethod parameters? - -RaiseEvent method service parameters have been removed from v9 and to name some reasons why: - -* Because it's entirely inconsistent, not all services have this as method parameters and maintaining that consistency is impossible especially if 3rd party libraries support events/notifications. -* It's hacky. There's no good way to suppress events/notifications this way at a higher (scoped) level. -* There's also hard-coded logic to ignore these parameters sometimes which makes it even more inconsistent. -* There are events below services at the repository level that cannot be controlled by this flag. - -**What do we use instead?** - -We can suppress notifications at the scope level which makes things consistent and will work for all services that use a Scope. Also, there's no required maintenance to make sure that new service methods will also work. - -**How to use scopes**: - -* Create an explicit scope and call scope.Notifications.Suppress(). -* The result of Suppress() is IDisposable, so until it is disposed, notifications will not be added to the queue. - -[Example](https://github.com/umbraco/Umbraco-CMS/blob/b69afe81f3f6fcd37480b3b0295a62af44ede245/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/SupressNotificationsTests.cs#L35): - -```csharp -using (IScope scope = ScopeProvider.CreateScope(autoComplete: true)) -using (IDisposable _ = scope.Notifications.Suppress()) -{ - // TODO: Calls to service methods here will not have notifications -} -``` - -Child scope will inherit the parent Scope's notification object which means if a parent scope has notifications suppressed, then so does the child scope. You cannot call Suppress() more than once for the same outer scope instance else an exception will be thrown. This ensures that you cannot un-suppress notifications at a child level for an outer scope. It also ensures that suppressing events is an explicit thing to do. - -**Why would one want to suppress events?** - -The main reason for ever doing this would be performance for bulk operations. The callers should be aware that suppressing events will lead to an inconsistent content cache state (if notifications are suppressed for content or media services). This is because notifications are used by NuCache to populate the cmsContentNu table and populate the content caches. They are also used to populate the Examine indexes. - -So if you did suppress events, it will require you to rebuild the NuCache and examine data manually. - -
diff --git a/10/umbraco-cms/reference/notifications/notification-handler.md b/10/umbraco-cms/reference/notifications/notification-handler.md deleted file mode 100644 index 7b2fb3f17cc..00000000000 --- a/10/umbraco-cms/reference/notifications/notification-handler.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -description: Learn about notification handlers lifetime, async notification handler and how to register the notification handlers. ---- - -# Notification handlers lifetime - -It's important to note that the handlers you create and register to receive notifications will be transient, this means that they will be initialized every time they receive a notification, so you cannot rely on them having a specific state based on previous notifications. For instance, you cannot create a list in a handler and add something when a notification is received, and then check if that list contains what you added in an earlier notification, that list will always be empty because the object has just been initialized. - -If you need persistence between notifications, we recommend that you move that functionality into a service or similar, and register it with the DI container, and then inject that into your handler. - -As previously mentioned a lot of notifications exist in pairs, with a "before" and "after" notification, there may be cases where you want to add some information to the "before" notification, which will then be available to your "after" notification handler, in order to support this, the notification "pairs" are stateful. This means that the notifications contain a dictionary that is shared between the "before" and "after" notification that you can add values to, and later get them from like this: - -```C# -public void Handle(TemplateSavingNotification notification) -{ - notification.State["SomeKey"] = "Some Value Relevant to the \"after\" notification handler"; -} - - -public void Handle(TemplateSavedNotification notification) -{ - var valueFromSaving = notification.State["SomeKey"]; -} -``` - -# Registering notification handlers - -Once you've made your notification handlers you need to register them with the `AddNotificationHandler` extension method on the `IUmbracoBuilder`, so they're run whenever a notification they subscribe to is published. There are two ways to do this: In the Startup class, if you're making handlers for your site, or a composer if you're a package developer subscribing to notifications. - -#### Registering notification handlers in the startup class - -In the Startup class register your notification handler in the `ConfigureServices` after `AddComposers()` but before `Build()`: - -```C# -public void ConfigureServices(IServiceCollection services) -{ -#pragma warning disable IDE0022 // Use expression body for methods - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddNotificationHandler() - .Build(); -#pragma warning restore IDE0022 // Use expression body for methods - -} -``` - -The extension method takes two generic type parameters, the first `ContentPublishingNotification` is the notification you wish to subscribe to, the second `DontShout` is the class that handles the notification. This class must implement `INotificationHandler<>` with the type of notification it handles as the generic type parameter, in this case, the DontShout class definition looks like this: - -```C# -public class DontShout : INotificationHandler -``` - -For the full handler implementation see [ContentService Notifications](contentservice-notifications.md). - -## Registering notification handlers in a composer - -If you're writing a package for Umbraco you won't have access to the Startup class, you can instead use a composer which gives you access to the `IUmbracoBuilder`, the rest is the same as when doing it in the Startup class: - -```C# -public class DontShoutComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - } -} -``` - -## Registering many notification handlers - -You may want to subscribe to a lot of notifications, in this case, your `ConfigureServices` method or composer might end up being quite cluttered. You can avoid this by creating your own `IUmbracoBuilder` extension method for your events, keeping everything neatly wrapped up in one place, such an extension method can look like this: - -```C# -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Services.Notifications; - -namespace MySite -{ - public static class UmbracoBuilderNotificationExtensions - { - public static IUmbracoBuilder AddDontShoutNotifications(this IUmbracoBuilder builder) - { - builder - .AddNotificationHandler() - .AddNotificationHandler() - .AddNotificationHandler(); - - return builder; - } - } -} -``` - -You can then register all these notifications by calling `AddDontShoutNotifications` in `ConfigureServices` or your composer, just like you would `AddNotificationHandler`: - -```C# -public void ConfigureServices(IServiceCollection services) -{ -#pragma warning disable IDE0022 // Use expression body for methods - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddDontShoutNotifications() - .Build(); -#pragma warning restore IDE0022 // Use expression body for methods - -} -``` diff --git a/10/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md b/10/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md deleted file mode 100644 index e39ff6116af..00000000000 --- a/10/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md +++ /dev/null @@ -1,84 +0,0 @@ -# Sending Allowed Children Notification - -The `SendingAllowedChildrenNotification` enables you to manipulate the Document Types that will be shown in the create menu when adding new content in the backoffice. - -## Usage - -With the example below we can ensure that a Document Type cannot be selected if the type already exists in the Content tree. - -```csharp -using System.Web; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications -{ - public class SendingAllowedChildrenNotificationHandler : INotificationHandler - { - public void Handle(SendingAllowedChildrenNotification notification) - { - const string contentIdKey = "contentId"; - - // Try get the id from the content item in the backoffice - var queryStringCollection = HttpUtility.ParseQueryString(notification.UmbracoContext.OriginalRequestUrl.Query); - - if (!queryStringCollection.ContainsKey(contentIdKey)) - { - return; - } - - var contentId = queryStringCollection[contentIdKey].TryConvertTo().ResultOr(-1); - - if (contentId == -1) - { - return; - } - - var content = notification.UmbracoContext.Content?.GetById(true, contentId); - - if (content is null) - { - return; - } - - // Allowed children as configured in the backoffice - var allowedChildren = notification.Children.ToList(); - - if (content.ChildrenForAllCultures is not null) - { - // Get all children of current page - var childNodes = content.ChildrenForAllCultures.ToList(); - - // If there is a Settings page already created, then don't allow it anymore - // You can also use the ModelTypeAlias property from your PublishedModel for comparison, - // like Settings.ModelTypeAlias if you have set models builder to generate SourceCode models - if (childNodes.Any(x => x.ContentType.Alias == "settings")) - { - allowedChildren.RemoveAll(x => x.Alias == "settings"); - } - } - - // Update the allowed children - notification.Children = allowedChildren; - } - } -} -``` - -You also need to register this notification handler. You can achieve this by updating the `Startup` class like: - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddNotificationHandler() - .Build(); -} -``` - -{% hint style="info" %} -For more information about registering notifications read the [Registering notification handlers](./) article. -{% endhint %} diff --git a/10/umbraco-cms/reference/notifications/umbracoapplicationlifetime-notifications.md b/10/umbraco-cms/reference/notifications/umbracoapplicationlifetime-notifications.md deleted file mode 100644 index 860551c4ad8..00000000000 --- a/10/umbraco-cms/reference/notifications/umbracoapplicationlifetime-notifications.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -description: Represents an Umbraco application lifetime (starting, started, stopping, stopped) notification ---- - -# Umbraco Application Lifetime Notifications - -Umbraco application lifetime notifications are published for the starting, started, stopping, and stopped events of the Umbraco runtime. These events implement the `IUmbracoApplicationLifetimeNotification` interface that contains a single `IsRestarting` property. - -An Umbraco application is restarted after an install or upgrade has been completed. You can use this property to prevent running code twice: on initial boot and restart. To prevent running code when the application is in the install or upgrade state, inject an `IRuntimeState` instance in your notification and inspect the `Level` property instead. - -## Usage - -Example usage of the UmbracoApplicationLifetime notifications: - -```C# -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Notifications; - -public class UmbracoApplicationNotificationComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - builder.AddNotificationHandler(); - builder.AddNotificationHandler(); - builder.AddNotificationHandler(); - } -} - -public class UmbracoApplicationNotificationHandler : INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler -{ - private readonly ILogger _logger; - - public UmbracoApplicationNotificationHandler(ILogger logger) => _logger = logger; - - public void Handle(UmbracoApplicationStartingNotification notification) => Log(notification, notification.IsRestarting); - - public void Handle(UmbracoApplicationStartedNotification notification) => Log(notification, notification.IsRestarting); - - public void Handle(UmbracoApplicationStoppingNotification notification) => Log(notification, notification.IsRestarting); - - public void Handle(UmbracoApplicationStoppedNotification notification) => Log(notification, notification.IsRestarting); - - private void Log(INotification notification, bool isRestarting) => _logger.LogInformation("{Type} - {IsRestarting}", notification.GetType().Name, isRestarting); -} -``` diff --git a/10/umbraco-cms/reference/plugins/README.md b/10/umbraco-cms/reference/plugins/README.md deleted file mode 100644 index 9681bc22c1b..00000000000 --- a/10/umbraco-cms/reference/plugins/README.md +++ /dev/null @@ -1,19 +0,0 @@ ---- - -needsV8Update: "false" -needsV9Update: "false" ---- - -# Plugins - -_The term 'Plugins' is referring to any types in Umbraco that are found in assemblies that are used to extend and/or enhance the Umbraco application. Plugins can also be added directly registered to their specific 'Resolver' if the plugin type is not public or if the Resolver type doesn't support finding types in assemblies._ - -What is a Resolver and what kinds of Resolvers are there? - -## [Creating a Resolver for a Plugin](creating-resolvers.md) - -Creating a single object and multiple object Resolver. - -## [Finding types](finding-types.md) - -Using the PluginManager to lookup types in assemblies to register in Resolvers. diff --git a/10/umbraco-cms/reference/plugins/creating-resolvers.md b/10/umbraco-cms/reference/plugins/creating-resolvers.md deleted file mode 100644 index 7e15625b5f0..00000000000 --- a/10/umbraco-cms/reference/plugins/creating-resolvers.md +++ /dev/null @@ -1,97 +0,0 @@ ---- - -needsV8Update: "false" -needsV9Update: "false" ---- - -# Creating Resolvers - -_A Resolver should be created for any plugin type. Resolvers are the standard way to retrieve/create/register plugin types._ - -## Creating a single object resolver - -As an example, we'll create a resolver to resolve an application error logger: - -```csharp -/// -/// An object resolver to return the IErrorLogger -/// -public class ErrorLoggerResolver : SingleObjectResolverBase -{ - internal ContentStoreResolver(IErrorLogger errorLogger) - : base(errorLogger) - { - } - - /// - /// Can be used by developers at runtime to set their IErrorLogger at app startup - /// - /// - public void SetErrorLogger(IErrorLogger errorLogger) - { - Value = errorLogger; - } - - /// - /// Returns the IErrorLogger - /// - public IErrorLogger ErrorLogger - { - get { return Value; } - } -} -``` - -All you need to do is inherit from `Umbraco.Core.ObjectResolution.SingleObjectResolverBase` and then add whatever constructors, properties and methods you would like to expose. - -In the example above we have a constructor that accepts a default `IErrorLogger`. Normally in Umbraco this resolver will be constructed in a `IBootManager` with a default object. The we expose a method to allow developers to change to a custom `IErrorLogger` at runtime called `SetErrorLogger`. Then we create a property to expose the `IErrorLogger` called ErrorLogger. - -Example: - -```csharp -// get the error logger -IErrorLogger logger = ErrorLoggerResolver.Current.ErrorLogger; - -// set the error logger (can only be done during application startup) -ErrorLoggerResolver.Current.SetErrorLogger(new MyCustomErrorLogger("../my-file-path")); -``` - -## Creating a multiple object resolver - -Creating a multiple object resolver is similar. As an example we'll create a LanguageConvertersResolver. - -{% hint style="info" %} -The naming convention for multiple objects resolvers are plural: We've named this LanguageConverter**s**Resolver with a pluralized 'Converters' to denote that this resolver returns multiple objects -{% endhint %} - -```csharp -public sealed class LanguageConvertersResolver : ManyObjectsResolverBase -{ - /// - /// Constructor - /// - /// - internal LanguageConvertersResolver(IEnumerable converters) - : base(converters) - { - } - - /// - /// Return the converters - /// - public IEnumerable Converters - { - get { return Values; } - } - -} -``` - -When creating a multiple object resolver you need to decide what lifetime scope the objects created and returned will have which is defined in the constructor created. The default constructor of the `ManyObjectsResolverBase` specifies that the objects created will have an Application based lifetime scope which means the objects will be singletons only one instance of each one will exist for the lifetime of the application. There are 3 lifetime scopes that can be specified: - -* ObjectLifetimeScope.Application - * One instance of each object will be created for the entire lifetime of the application (singleton) -* ObjectLifetimeScope.Transient - * A new instance of each object will be created each time the 'Values' collection is accessed -* ObjectLifetimeScope.HttpRequest - * One instance of each object will be created for the lifetime of the current http request diff --git a/10/umbraco-cms/reference/plugins/finding-types.md b/10/umbraco-cms/reference/plugins/finding-types.md deleted file mode 100644 index 5e0044131a1..00000000000 --- a/10/umbraco-cms/reference/plugins/finding-types.md +++ /dev/null @@ -1,41 +0,0 @@ ---- - -needsV8Update: "false" -needsV9Update: "false" ---- - -# Finding types - -_Whenever types need to be found in assemblies in order to add them to resolvers, the PluginManager should be used. The TypeFinder should never be used directly in any code except for in PluginManager extension methods or in the PluginManager itself._ - -## The Plugin Manager - -The `Umbraco.Core.PluginManager` class is responsible for finding and caching all plugin types. It is also responsible for instantiating these types. It contains 4 important methods: - -* `IEnumerable ResolveTypes()` - * Generic method to find the specified type and cache the result -* `IEnumerable ResolveTypesWithAttribute()` - * Generic method to find the specified type that has an attribute and cache the result -* `IEnumerable ResolveAttributedTypes()` - * Generic method to find any type that has the specified attribute and cache the result -* `T CreateInstance(Type type, bool throwException = false)` - * Used to create an instance of the specified type based on the resolved/cached plugin types - -## Retrieving instances - -It is definitely possible to use the methods above to find types in your code but this is not recommended practice. It is recommended to create extension methods for the PluginManager named accordingly to find specific types. For example: - -```csharp -PluginManager.Current.ResolveTrees(); -``` - -The code for this method is as follows: - -```csharp -internal static IEnumerable ResolveTrees(this PluginManager resolver) -{ - return resolver.ResolveTypes(); -} -``` - -The code calls the PluginManager's ResolveTypes method but this method is human readable and distinguishable. diff --git a/10/umbraco-cms/reference/querying/README.md b/10/umbraco-cms/reference/querying/README.md deleted file mode 100644 index 5fd6b9dbeff..00000000000 --- a/10/umbraco-cms/reference/querying/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Querying & Models - -_Overview of multiple ways of querying, filtering, and searching published content for use on your website._ - -## [UDI identifiers](udi-identifiers.md) - -Umbraco stores identifiers in UDI format for most Umbraco object types. This identifier stores all of the metadata required to retrieve an Umbraco object and is parse-able within text. Example: `umb://document/4fed18d8c5e34d5e88cfff3a5b457bf2`. UDI's can be used in many of the querying APIs. - -## [IPublishedContent](ipublishedcontent/) - -`IPublishedContent` is strongly typed model for content, media and members that is used to render content in your views for your website. - -## [UmbracoHelper](umbracohelper.md) - -UmbracoHelper is the unified way to work with published content/media on your website. Whether you are using MVC or WebForms you will be able to use UmbracoHelper to query/traverse Umbraco published data. - -## [IMemberManager](imembermanager.md) - -`IMemberManager` is an user manager interface for accessing member data in the form of `MemberIdentityUser` and converting it to `IPublishedContent`. - -## [IPublishedContentQuery](ipublishedcontentquery.md) - -The `IPublishedContentQuery` interface contains query methods for accessing strongly typed content in services etc. - -## [ITagQuery](itagquery.md) - -The `ITagQuery` interface allows to work with tags in Umbraco. - -## [UmbracoContext](umbraco-context.md) - -The UmbracoContext is a simplified way to work with the current request on your website. diff --git a/10/umbraco-cms/reference/querying/imembermanager.md b/10/umbraco-cms/reference/querying/imembermanager.md deleted file mode 100644 index 409bb5d69d1..00000000000 --- a/10/umbraco-cms/reference/querying/imembermanager.md +++ /dev/null @@ -1,221 +0,0 @@ ---- - - -meta.Title: Umbraco IMemberManager -description: Using the IMemberManager1 ---- - -# IMemberManager - -`IMemberManager` is an user manager interface for accessing member data in the form of `MemberIdentityUser` and converting it to `IPublishedContent`. `IMemberManager` has a variety of methods that are useful in views and controllers. For the list of methods, see the [IMemberManager Interface API Documentation](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Security.IMemberManager.html#methods). - -## How to reference IMemberManager - -There are different ways to reference MembershipHelper: - -### Views - -While working with templates, the methods are available when you inject `@IMemberManager` to access member data: - -```csharp -@using Umbraco.Cms.Core.Services; -@inject IMemberManager _memberManager; - -_memberManager.IsLoggedIn() -``` - -### Dependency Injection - -If you wish to use the `IMemberManager` in a class that inherits from one of the Umbraco base classes (eg. `SurfaceController`, `UmbracoApiController`, or `UmbracoAuthorizedApiController`), you can use Dependency Injection. For instance, if you have registered your own class in Umbraco's dependency injection, you can specify the `IMemberManager` interface in your constructor: - -```csharp -public class MemberAuthenticationSurfaceController : SurfaceController -{ - private readonly IMemberManager _memberManager; - - public MemberAuthenticationSurfaceController(IMemberManager memberManager) - { - _memberManager = memberManager; - } -} -``` - -## Examples - -### Finding members - -`IMemberManager` has multiple ways to find members. - -#### FindByIdAsync(string) - -Finds a member by their ID - -``` -@{ - var memberById = await _memberManager.FindByIdAsync("1234"); - // Do stuff with the member, for instance checking if email is confirmed - var emailConfirmed = memberById.EmailConfirmed; -} -``` - -If we want to find a member by `Udi` or `Guid` we need to to inject `IIdKeyMap` service: - -**Find member by `Udi`** - -``` -var memberUdiAttempt = _idKeyMap.GetIdForUdi(nodeUdi); -if (memberUdiAttempt.Success) -{ - var memberId = memberUdiAttempt.Result; - var member = await _memberManager.FindByIdAsync(memberId.ToString()); -} -``` - -**Find member by `Guid`** - -``` -var memberKeyAttempt = _idKeyMap.GetIdForKey(nodeKey); -if (memberKeyAttempt.Success) -{ - var memberId = memberKeyAttempt.Result; - var member = await _memberManager.FindByIdAsync(memberId.ToString()); -} -``` - -#### FindByEmailAsync(string) - -Finds a member by their email. - -``` -@{ - var memberById = await _memberManager.FindByEmailAsync("test@member.com"); - // Do stuff with the member, for instance checking if email is confirmed - var emailConfirmed = memberById.EmailConfirmed; -} -``` - -#### FindByNameAsync(string) - -Finds a member by their login name. - -``` -@{ - var memberById = await _memberManager.FindByNameAsync("TestLoginName"); - // Do stuff with the member, for instance checking if email is confirmed - var emailConfirmed = memberById.EmailConfirmed; -} -``` - -### AsPublishedMember(MemberIdentityUser) - -By default `IMemberManager` returns members as `MemberIdentityUser`. This method allows you to convert a `MemberIndentityUser` into `IPublishedContent`: - -``` -@{ - MemberIdentityUser memberById = await _memberManager.FindByEmailAsync("test@member.com"); - IPublishedContent memberAsContent = _memberManager.AsPublishedMember(memberById); -} -``` - -### GetCurrentMemberAsync() - -Returns the currently logged in member if there is one, else returns null value. - -``` -@{ - var currentMember = await _memberManager.GetCurrentMemberAsync(); -} - -@if (currentMember is not null) -{ -

A member is logged in, member username: @currentMember.UserName

-} -else -{ -

No member is logged in.

-} -``` - -### GetUserIdAsync() - -Returns the user id of a user - -``` -@{ - var userId = await _memberManager.GetUserIdAsync(user); -} -``` - -### IsLoggedIn() - -Checks if a member is logged in. - -``` -@if (_memberManager.IsLoggedIn()) -{ -

A member is logged in

-} -else -{ -

No member is logged in.

-} -``` - -### IsMemberAuthorizedAsync(IEnumerable memberTypes, IEnumerable memberGroups, IEnumerable memberIds) - -Checks if the current member is authorized for content protected by types, groups or specific members. For instance, you can use this method to check if the current logged in member is authorized. This is particularly useful for pages only available to the VIP member group, like so: - -``` -@{ - var memberIsAuthorized = await _memberManager.IsMemberAuthorizedAsync(allowGroups: new []{"VIP"}); -} -``` - -### IsProtectedAsync() - -Returns a `Task` specifying if the page with a given [Umbraco path](ipublishedcontent/properties.md#path) has public access restrictions set. - -```csharp -
    - @foreach (var child in Model.Children) - { - @if (await _memberManager.IsProtectedAsync(child.Path)) - { -
  • @child.Name - Members only!
  • - } - else - { -
  • @child.Name - Access to everyone!
  • - } - } -
-``` - -### MemberHasAccessAsync(string) - -Returns a `Task` specifying if the currently logged in member has access to the page given its [Umbraco path](ipublishedcontent/properties.md#path). - -```csharp -
    - @foreach (var child in Model.Children) - { - // Only display the page if the current member has access to it. - @if (await _memberManager.MemberHasAccessAsync(child.Path)) - { -
  • @child.Name
  • - } - } -
-``` - -`MemberManager` can also be used to manage users. - -### ValidateCredentialsAsync(string username, string password) - -Validates that a user's credentials are correct without logging them in. - -``` -@{ - var isValidCredentials = await _memberManager.ValidateCredentialsAsync(userName, password); -} -``` diff --git a/10/umbraco-cms/reference/querying/ipublishedcontent/README.md b/10/umbraco-cms/reference/querying/ipublishedcontent/README.md deleted file mode 100644 index 659dd41ab2e..00000000000 --- a/10/umbraco-cms/reference/querying/ipublishedcontent/README.md +++ /dev/null @@ -1,33 +0,0 @@ ---- - - ---- - -# IPublishedContent - -_`IPublishedContent` is a strongly typed model for content, media and members and is used to render content in your views for your website._ - -## Get started - -To access the current page in your templates, copy-paste the below Razor code. - -```csharp -@{ - var pageName = Model.Name; - var childPages = Model.Children; -} - -

@pageName

-``` - -## [Properties & Extension Methods](properties.md) - -Listing and explanation of IPublishedContent properties and standard helpers for Content and Media. - -## [Collections & Filtering](collections.md) - -Methods for IPublishedContent collections and filtering. - -## [IsHelpers](ishelpers.md) - -A library of extension methods to simplify working with IPublishedContent in collections to modify your HTML output. Examples of using `IsHelpers` could be injecting CSS classes for alternating rows or to modify margins. diff --git a/10/umbraco-cms/reference/querying/ipublishedcontent/collections.md b/10/umbraco-cms/reference/querying/ipublishedcontent/collections.md deleted file mode 100644 index de150990899..00000000000 --- a/10/umbraco-cms/reference/querying/ipublishedcontent/collections.md +++ /dev/null @@ -1,223 +0,0 @@ ---- - - ---- - -# IPublishedContent Collections - -All collections of `IPublishedContent` are `IEnumerable`. This means that all C# LINQ statements can be used to filter and query the collections. - -## Collections - -### .Children - -Returns a collection of child items available in the current culture, below the current content item. - -```csharp -
    - @foreach(var item in Model.Children) - { -
  • @item.Name
  • - } -
-``` - -### .ChildrenForAllCultures - -Returns a collection of child items for all cultures, below the current content item, regardless of whether they are available for the current culture. - -```csharp -
    - @foreach(var item in Model.ChildrenForAllCultures) - { -
  • @item.Name
  • - } -
-``` - -### .Children(string culture = null) - -Returns a collection of child items available in the specified culture with a default of the current one, below the current content item. - -```csharp -
    - @foreach(var item in Model.Children("dk-dk")) - { -
  • @item.Name
  • - } -
-``` - -### .Ancestors() - -Returns all ancestors of the current page (parent page, grandparent and so on) - -```csharp -
    - @*Order items by their Level*@ - @foreach(var item in Model.Ancestors().OrderBy(x => x.Level)) - { -
  • @item.Name
  • - } -
-``` - -### .Ancestor() - -Returns the first ancestor of the current page - -```csharp -@* return the first ancestor item from the current page *@ -var nodes = Model.Ancestor(); - -@* return the first item, of a specific type, from the current page *@ -var nodes = Model.Ancestor(); -``` - -### .AncestorsOrSelf() - -Returns a collection of all ancestors of the current page (parent page, grandparent and so on), and the current page itself - -```csharp -@* Get the top item in the content tree, this will always be the Last ancestor found *@ -var websiteRoot = Model.AncestorsOrSelf().Last(); -``` - -### .Descendants() - -Returns all descendants of the current page (children, grandchildren etc) - -```csharp -
    - @* Filter collection by content that has a template assigned *@ - @foreach(var item in Model.Descendants().Where(x => x.TemplateId > 0)) - { -
  • @item.Name
  • - } -
-``` - -### .DescendantsOrSelf() - -Returns all descendants of the current page (children, grandchildren etc), and the current page itself - -```csharp -
    - @* Filter collection by content that has a template assigned *@ - @foreach(var item in Model.DescendantsOrSelf().Where(x => x.TemplateId > 0)) - { -
  • @item.Name
  • - } -
-``` - -### .OfTypes - -Filters a collection of content by content type alias - -```csharp -
    - @* Filter collection by content type alias (you can pass in any number of aliases) *@ - @foreach(var item in Model.DescendantsOrSelf().OfTypes("widget1", "widget2")) - { -
  • @item.Name
  • - } -
-``` - - - -## Filtering, Ordering & Extensions - -Filtering and Ordering are done with LINQ. - -Some examples: - -### .Where - -```csharp -@* Returns all items in the collection that have a template assigned and have a name starting with 'S' *@ -var nodes = Model.Descendants().Where(x => x.TemplateId > 0 && x.Name.StartsWith("S")) -``` - -### .OrderBy - -```csharp -@* Orders a collection by the property name "title" *@ -var nodes = Model.Children.OrderBy(x => x.GetProperty("title")) -``` - -### .GroupBy - -Groups collection by content type alias - -```csharp -@{ - var groupedItems = Model.Descendants().GroupBy(x => x.ContentType); - foreach (var group in groupedItems) - { -

@group.Key.Alias

- foreach(var item in group) - { -

@item.Name

- } - } -} -``` - -### .Take(int) - -Return only the number of items for a collection specified by the integer value. - -```csharp -@* return the first 3 items from the child collection *@ -var nodes = Model.Children.Take(3); -``` - -### .Skip(int) - -Return items from the collection after skipping the specified number of items. - -```csharp -@* Skip the first 3 items in the collection and return the rest *@ -var nodes = Model.Children.Skip(3); -``` - -{% hint style="info" %} -You can combine Skip and Take when using for paging operations -{% endhint %} - -```csharp -@* using skip and take together you can perform paging operations *@ -var nodes = Model.Children.Skip(10).Take(10); -``` - -### .Count() - -Returns the number of items in the collection - -```csharp -int numberOfChildren = Model.Children.Count(); -``` - -### .Any() - -Returns a boolean True/False value determined by whether there are any items in the collection - -```csharp -bool hasChildren = Model.Children.Any(); -``` - -## Filtering Conventions - -Some filtering and routing behaviour is dependent upon a set of special naming conventions for certain properties. [See also: Routing Property Conventions](../../routing/routing-properties.md) - -### .IsVisible() - -If you create a checkbox property on a document type with an alias `umbracoNaviHide` then the value of this property is used by the `IsVisible()` extension method when filtering. - -```csharp -IEnumerable sectionPages = Model.Children.Where(x => x.IsVisible()); -``` - -Use case: When displaying a navigation menu for a section of the site, following this convention gives editors the option to 'hide' certain pages from appearing in the section navigation. (hence the unusual _umbracoNaviHide_ property alias!) diff --git a/10/umbraco-cms/reference/querying/ipublishedcontent/ishelpers.md b/10/umbraco-cms/reference/querying/ipublishedcontent/ishelpers.md deleted file mode 100644 index ae6891016db..00000000000 --- a/10/umbraco-cms/reference/querying/ipublishedcontent/ishelpers.md +++ /dev/null @@ -1,74 +0,0 @@ ---- - - ---- - -# IPublishedContent IsHelpers - -The IsHelper methods are a set of extension methods for IPublishedContent to help perform quick conditional queries against IPublishedContent nodes in a collection. - -IsHelper methods are ternary operators, however they work a little nicer since they can be embedded in properties. They are also quicker to write because fewer brackets are needed for Razor to understand them. - -## How to use - -An IsHelper can be invoked as a method of an `IPublishedContent`. - -```csharp -@{ -if(item.IsVisible()) -{ -@item.Name -} -} -``` - - - -## IsHelper Methods - -### IsComposedOf(string alias) - -Test whether the content is of a content type composed of the given alias. - -### IsAllowedTemplate(int templateId) - -Test whether the specified `templateId` is an allowed template for the current node. - -### IsAllowedTemplate(string templateAlias) - -Test whether the specified `templateAlias` is an allowed template for the current node. - -{% hint style="info" %} -By default the above template methods are disabled. To enable them, make sure to modify your appsettings.json to include the following JSON config keys inside Umbraco.CMS section: - -```json -"WebRouting": { - "ValidateAlternativeTemplates": true, - "DisableAlternativeTemplates": false - } -``` -{% endhint %} - -### .IsEqual(IPublishedContent otherNode\[,string valueIfTrue]\[,string valueIfFalse]) - -Test if the current node is equal (by Id) to another node. - -### .IsNotEqual(IPublishedContent otherNode\[,string valueIfTrue]\[,string valueIfFalse]) - -Test if the current node is not equal (by Id) to another node. - -### .IsDescendant(IPublishedContent otherNode\[,string valueIfTrue]\[,string valueIfFalse]) - -Test if the current node is a descendant of another node. - -### .IsDescendantOrSelf(IPublishedContent otherNode\[,string valueIfTrue]\[,string valueIfFalse]) - -Test if the current node is the same as or a descendant of another node. - -### .IsAncestor(IPublishedContent otherNode\[,string valueIfTrue]\[,string valueIfFalse]) - -Test if the current node is an ancestor of another node. - -### .IsAncestorOrSelf(IPublishedContent otherNode\[,string valueIfTrue]\[,string valueIfFalse]) - -Test if the current node is the same as or an ancestor of another node. diff --git a/10/umbraco-cms/reference/querying/ipublishedcontent/properties.md b/10/umbraco-cms/reference/querying/ipublishedcontent/properties.md deleted file mode 100644 index 447191709e1..00000000000 --- a/10/umbraco-cms/reference/querying/ipublishedcontent/properties.md +++ /dev/null @@ -1,300 +0,0 @@ ---- - - ---- - -# IPublishedContent Property Access & Extension Methods - -## Umbraco Properties - -Built-in properties, which exists on all content objects by default - -Common Examples - -```csharp -@* gets the current page Url *@ -@Model.Url(PublishedUrlProvider) - -@* gets the Creation date, and formats it to a short date *@ -@Model.CreateDate.ToString("D") - -@* Outputs the name of the parent if it exists *@ -@if(Model.Parent != null){ -

@Model.Parent.Name

-} -``` - -### .Id - -Returns the unique Id for the current content item - -```csharp -@Model.Id -``` - -### .Name - -Returns the Name of the current content item in the current culture - -```csharp -@Model.Name -``` - -### .Name(IVariationContextAccessor, string culture = null) - -Returns the Name of the current content item in the specified culture, null falls back to the current culture - -```csharp -@Model.Name(VariationContextAccessor, "dk-dk") -``` - -### .ContentType - -Returns a strongly typed 'PublishedContentType' object representing the content type the IPublishedContent item is based on, that gives access to the alias - -```csharp -@Model.ContentType -@Model.ContentType.Alias -``` - -### .GetCultureFromDomains(IUmbracoContextAccessor, ISiteDomainHelper, Uri current = null) - -Returns a culture from a configured domain in the content tree. - -```csharp -@Model.GetCultureFromDomains(ContextAccessor, DomainHelper) -``` - -### .Parent - -Returns the parent content item - -```csharp -@Model.Parent -@Model.Parent.Name -``` - -### .Path - -Returns a comma delimited string of Node Ids that represent the path of content items back to root. - -```csharp -@Model.Path -``` - -### .Level - -Returns the Level (depth) this content item is in its tree path - -```csharp -@Model.Level -``` - -### .TemplateId - -Returns the id of the default Template object used with this content item. - -```csharp -@Model.TemplateId -``` - -There are extension methods to retrieve template alias (Model.GetTemplateAlias()) - -### .SortOrder - -Returns the index the page is on, compared to its siblings - -```csharp -@Model.SortOrder -``` - -### .Url(PublishedUrlProvider, culture = null, UrlMode mode = UrlMode.Default) - (Extension method) - -Returns the Url to the page. - -```csharp -@Model.Url(PublishedUrlProvider) -``` - -**Example:** Getting a Danish Url for a site where a Danish language has been set up. - -```csharp -@Model.Url(PublishedUrlProvider, "dk") -``` - -**Example:** Getting an Absolute Danish Url for a site where a Danish language has been set up. - -```csharp -@Model.Url(PublishedUrlProvider, "dk", UrlMode.Absolute) -``` - -### .UrlSegment - -Returns the Url encoded name of the page (slug) of the current culture - -```csharp -@Model.UrlSegment -``` - -### .UrlSegment(IVariationContextAccessor, string culture = null) - -Returns the Url encoded name of the page (slug) of the specified culture - -```csharp -@Model.UrlSegment(VariationContextAccessor) -``` - -### .WriterId - -Returns the id of the Umbraco backoffice user that performed the last update operation on the content item. - -```csharp -@Model.WriterId -``` - -### .WriterName(IUserService) - -Returns the name of the Umbraco backoffice user that initially created the content item. - -```csharp -@Model.WriterName(UserService) -``` - -### .CreatorId - -Returns the id of the Umbraco backoffice user that initially created the content item - -```csharp -@Model.CreatorId -``` - -### .CreatorName(IUserService) - -Returns the name of the Umbraco backoffice user that initially created the content item. - -```csharp -@Model.CreatorName(UserService) -``` - -### .CreateDate - -Returns the DateTime the page was created - -```csharp -@Model.CreateDate -@* gets the Creation date, and formats it to a short date *@ -@Model.CreateDate.ToString("D") -``` - -### .UpdateDate - -Returns the DateTime the page was modified - -```csharp -@Model.UpdateDate -@* gets the Update/Modified date, and formats it to a short date *@ -@Model.UpdateDate.ToString("D") -``` - - - -## Custom properties - -All content and media items contain a reference to all the data defined by their Document Type. Custom property access is achieved using variations of the method: `Value` - -### Model.Value(IPublishedValueFallback, string) - -Returns the property value for the specified property alias - -```csharp -@*Get the property with alias: "siteName" from the current page *@ -@Model.Value(PublishedValueFallback, "siteName") -``` - -The type returned of this property value is `object`. This is fine in most cases since when using the above syntax, Razor will automatically execute a `ToString()` on the result value. - -See `Model.Value(string)` for how to return a strongly typed object for the property - -### Model.Value\(string) - -Returns the property value for the specified property alias converted to 'T' - the requested output type of the property value. - -For example, to return the `string` result of "siteName": - -```csharp -@(Model.Value(PublishedValueFallback, "siteName")) -``` - -```csharp -var mediaItems = Model.Value>(PublishedValueFallback, "mediaIds"); -``` - -## Fallbacks - -If the current content item doesn't have the requested value, use an alternative 'fallback' value in its place. - -Each of the examples below make use of an injected `PublishedValueFallback`. This is achieved by adding the following at the top of your Razor file: - -```csharp -@inject IPublishedValueFallback PublishedValueFallback -``` - -This parameter is optional, but can make unit testing easier. - -### Fallback to Default Value - -If a content page has a 'title' property, to fallback to use the 'Name' of the content item if the 'title' is not populated. Set the Fallback type to be Fallback.ToDefaultValue, and set the DefaultValue accordingly: - -```csharp -@(Model.Value(PublishedValueFallback, "title", fallback: Fallback.ToDefaultValue, defaultValue: Model.Name)); -``` - -or to a specific value - -```csharp -@(Model.Value(PublishedValueFallback, "author", fallback: Fallback.ToDefaultValue, defaultValue: "Team Reporter")); -``` - -### Fallback to Ancestors - -Look for a property value on the current page. If it doesn't exist look for the property value on the parent page. Then the parent's parent page and so on. This approach allows specifying 'global property values' all the way up the content tree. These values can be overridden in different sections or individual pages. - -```csharp -@(Model.Value(PublishedValueFallback, "propertyAlias", fallback: Fallback.ToAncestors)) -``` - -### Fallback to Language - -If working with variants - fallback to a different language value - if perhaps the value hasn't been populated yet for the current language: - -```csharp -@(Model.Value(PublishedValueFallback, "pageTitle", "fr", fallback: Fallback.ToLanguage)) -``` - -### Combining the Fallback options - -Use Fallback.To() to 'combine' Fallback options. - -The following would first look for a 'title' property on all ancestors, before defaulting to the current page's name: - -```csharp -@Model.Value(PublishedValueFallback, "title", fallback: Fallback.To(Fallback.Ancestors, Fallback.DefaultValue), defaultValue: Model.Name) -``` - -## Property Methods - -**There are a few helpful methods to help check if a property exists, has a value or is null.** - -### .HasProperty(string propertyAlias) - -Returns a boolean value representing if the IPublishedContent has a property with the specified alias. - -### .HasValue(string propertyAlias) - -Returns a boolean value representing if the IPublishedContent property has had a value set. - -It's possible to use 'Fallbacks' with HasValue: - -```csharp -bool hasPageTitleSetSomewhere = Model.HasValue(PublishedValueFallback, "pageTitle", fallback: Fallback.ToAncestors); -``` diff --git a/10/umbraco-cms/reference/querying/ipublishedcontentquery.md b/10/umbraco-cms/reference/querying/ipublishedcontentquery.md deleted file mode 100644 index 41ec428d236..00000000000 --- a/10/umbraco-cms/reference/querying/ipublishedcontentquery.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -meta.Title: Umbraco IPublishedContentQuery -description: Querying in views with IPublishedContentQuery in Umbraco ---- - -# IPublishedContentQuery - -The `IPublishedContentQuery` interface contains different query methods for accessing strongly typed content in services etc. - -## How to inject IPublishedContentQuery - -In order to inject the `IPublishedContentQuery` into your services, you must add a using statement for `Umbraco.Cms.Core` and inject the service using the constructor. - -```C# -using Umbraco.Cms.Core; - -namespace Umbraco.Docs.Samples.Web.Services -{ - public class SearchService - { - private readonly IPublishedContentQuery _publishedContentQuery; - - public SearchService(IPublishedContentQuery publishedContentQuery) - { - _publishedContentQuery = publishedContentQuery; - } - } -} -``` - -Now you can access the `IPublishedContentQuery` through `_publishedContentQuery` - -## Examples - -### .Search(string term) - -By default, `IPublishedContentQuery` will search on Umbraco's 'External' search index for any published content matching the provided search term. - -```csharp -public IEnumerable Search(string searchTerm) -{ - foreach (var result in _publishedContentQuery.Search(searchTerm)) - { - yield return result; - } -} -``` - -### .Search(string term, int skip, int take, out long totalRecords) - -Specifying the number of records 'to skip' and the number of records 'to take' improves performance with many matching search results. This approach is beneficial when there is a requirement to implement paging. - -```csharp -public IEnumerable Search(string searchTerm, int skip = 5, int take = 10) -{ - foreach (var result in _publishedContentQuery.Search(searchTerm, skip, take, out long totalRecords)) - { - yield return result; - } -} -``` - -### .Search(IQueryExecutor queryExecutor) - -For more complex searching you can construct an Examine QueryExecutor. In the example the search will execute against content of type "blogPost" only. [Further information on using Examine](../searching/examine/quick-start.md#different-ways-to-query) - -```csharp -using System; -using System.Collections.Generic; -using Examine; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Infrastructure.Examine; -using Umbraco.Extensions; - -namespace Umbraco.Docs.Samples.Web.Services -{ - public class SearchService - { - private readonly IPublishedContentQuery _publishedContentQuery; - private readonly IExamineManager _examineManager; - - public SearchService(IPublishedContentQuery publishedContentQuery, IExamineManager examineManager) - { - _publishedContentQuery = publishedContentQuery; - _examineManager = examineManager; - } - - public IEnumerable Search(string searchTerm) - { - if (!_examineManager.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out IIndex index)) - { - throw new InvalidOperationException($"No index found by name{Constants.UmbracoIndexes.ExternalIndexName}"); - } - - var query = index.Searcher.CreateQuery(IndexTypes.Content); - var queryExecutor = query.NodeTypeAlias("blogPost").And().ManagedQuery(searchTerm); - - foreach (var result in _publishedContentQuery.Search(queryExecutor)) - { - yield return result; - } - } - } -} -``` diff --git a/10/umbraco-cms/reference/querying/itagquery.md b/10/umbraco-cms/reference/querying/itagquery.md deleted file mode 100644 index cd205aeed38..00000000000 --- a/10/umbraco-cms/reference/querying/itagquery.md +++ /dev/null @@ -1,161 +0,0 @@ ---- - - -meta.Title: "Umbraco Tag Query" -description: "Working with tags in Umbraco" ---- - -# ITagQuery - -The `ITagQuery` interface is your primary way to work with tags in Umbraco. This interface allows you to get different tags, such as content tags and media tags. It also lets you retrieve content by tag, for instance, getting all content nodes with the "Umbraco" tag. - -## How to reference ITagQuery - -If you're using it in Views or Partial views you can inject `ITagQuery` using the `@inject` keyword, for example - -```C# -@inject ITagQuery _tagQuery; -``` - -After this you can use `_tagQuery` to access the `ITagQuery`. - -If you're using it in controllers, you can inject it into the constructor like so: - -```C# -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Web.Common.Controllers; - -namespace UmbracoHelperDocs.Controllers -{ - [Route("tags/[action]")] - public class TagApiController : UmbracoApiController - { - private readonly ITagQuery _tagQuery; - - public TagApiController(ITagQuery tagQuery) - { - _tagQuery = tagQuery; - } - - public ActionResult> GetMediaTags() - { - return _tagQuery.GetAllMediaTags().Select(tag => tag.Text).ToList(); - } - } -} -``` - -{% hint style="warning" %} -`ITagQuery` is a scoped service, meaning that it should only be injected into scoped or transient services. For more information see the official [Microsoft Documentation](https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#scoped) -{% endhint %} - -## Examples - -All examples are from a view using the injection shown above, but working with tags in controllers will be the same. - -### GetAllContentTags([string tagGroup]) - -Get a collection of tags used by content items on the site. Optionally, you can pass in a group name to only list tags belonging to a specific tag group - -```csharp -@{ - var allContentTags = _tagQuery.GetAllContentTags(); - var newsContentTags = _tagQuery.GetAllContentTags("news"); -} -``` - -### GetAllMediaTags([string tagGroup]) - -Get a collection of tags used by media items on the site. Optionally, you can pass in a group name to only list tags belonging to a specific tag group - -```csharp -@{ - var allMediaTags = _tagQuery.GetAllMediaTags(); - var newsMediaTags = _tagQuery.GetAllMediaTags("news"); -} -``` - -### GetAllMemberTags([string tagGroup]) - -Get a collection of tags used by members on the site. Optionally, you can pass in a group name to only list tags belonging to a specific tag group - -```csharp -@{ - var allMemberTags = _tagQuery.GetAllMemberTags(); - var newsMemberTags = _tagQuery.GetAllMemberTags("news"); -} -``` - -### GetAllTags([string tagGroup]) - -Get a collection of tags used on the site. Optionally, you can pass in a group name to only list tags belonging to a specific tag group - -```csharp -@{ - var allTags = _tagQuery.GetAllTags(); - var allNewsTags = _tagQuery.GetAllTags("news"); -} -``` - -### GetContentByTag(string tag, [string tagGroup]) - -Get a collection of IPublishedContent by tag, and you can optionally filter by tag group as well - -```csharp -@{ - var taggedContent = _tagQuery.GetContentByTag("News"); -} -``` - -### GetContentByTagGroup(string tagGroup) - -Get a collection of IPublishedContent by tag group - -```csharp -@{ - var taggedContent = _tagQuery.GetContentByTagGroup("BlogTags"); -} -``` - -### GetMediaByTag(string tag, [string tagGroup]) - -Get a collection of Media by tag, and you can optionally filter by tag group as well - -```csharp -@{ - var taggedMedia = _tagQuery.GetMediaByTag("BlogTag"); -} -``` - -### GetMediaByTagGroup(string tag, [string tagGroup]) - -Get a collection of Media by tag group - -```csharp -@{ - var mediaByTagGroup = _tagQuery.GetMediaByTagGroup("BlogTags"); -} -``` - -### GetTagsForEntity(int contentId, [string tagGroup]) - -Get a collection of tags by entity id (queries content, media and members), and you can optionally filter by tag group as well - -```csharp -@{ - var tagsForEntity = _tagQuery.GetTagsForEntity(1234); -} -``` - -### GetTagsForProperty(int contentId, string propertyTypeAlias, [string tagGroup]) - -Get a collection of tags assigned to a property of an entity (queries content, media and members). Optionally, you can filter by tag group as well - -```csharp -@{ - var propertyTags = _tagQuery.GetTagsForProperty(1234, "propertyTypeAlias"); -} -``` \ No newline at end of file diff --git a/10/umbraco-cms/reference/querying/udi-identifiers.md b/10/umbraco-cms/reference/querying/udi-identifiers.md deleted file mode 100644 index 3f6b0a5b672..00000000000 --- a/10/umbraco-cms/reference/querying/udi-identifiers.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -versionFrom: 7.6.0 - ---- - -# UDI Identifiers - -## Introduction - -Umbraco stores identifiers in UDI format for most Umbraco object types. This identifier stores all of the metadata required to retrieve an Umbraco object and is parse-able within text. Example: `umb://document/4fed18d8c5e34d5e88cfff3a5b457bf2`. UDI's can be used in many of the querying APIs. - -{% hint style="info" %} -UDI is currently not an acronym for something. There is no official definition of what it's short for. Therefore it's called *UDI* -{% endhint %} - -## Format - -An Umbraco UDI consists of three parts: the scheme, the type and a GUID Identifier. For example: `umb://document/4fed18d8c5e34d5e88cfff3a5b457bf2`. - -Breaking it down: - -1. The scheme is `umb://` - this is always the same and makes it identifiable as an Umbraco UDI -2. The type is `document` - so in this is an Umbraco node, but it could also be `media`, `member`, etc. -3. The GUID Id is `4fed18d8c5e34d5e88cfff3a5b457bf2` - this is a GUID (dashes removed) which is randomly generated when the item is being created - -## Usage - -You can use UDIs in some of the Querying and Management/Service APIs. - -There are 2 types of UDIs: - -## GUID UDI - -* [API Reference for Umbraco 9](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.GuidUdi.html) -* [API Reference for Umbraco 10](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.GuidUdi.html) - - -## String UDI - -* [API Reference for Umbraco 9](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.StringUdi.html) -* [API Reference for Umbraco 10](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.StringUdi.html) \ No newline at end of file diff --git a/10/umbraco-cms/reference/querying/umbraco-context.md b/10/umbraco-cms/reference/querying/umbraco-context.md deleted file mode 100644 index cce023f1e79..00000000000 --- a/10/umbraco-cms/reference/querying/umbraco-context.md +++ /dev/null @@ -1,70 +0,0 @@ ---- - -meta.Title: "Umbraco Request Context" -description: "The UmbracoContext is a helpful service provided on each request to the website" ---- - -# UmbracoContext helper - -The UmbracoContext is the simplified way to work with the current request on your website. - -You can use UmbracoContext to access the content and media cache. Other useful properties are the original and cleaned URLs of the current request. You can also check if the current request is running in "preview" mode. - -## How to reference UmbracoContext - -If you are using Views or Partial View Macros you can reference the UmbracoContext with the syntax: `@UmbracoContext` - -If you need an `UmbracoContext` in your own controllers, you need to inject an `IUmbracoContextAccessor`. - -The following is an example of how to get access to the `UmbracoContext` in a controller: - -```C# -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; -using Umbraco.Cms.Web.Common.PublishedModels; -using Umbraco.Extensions; - -namespace Umbraco.Docs.Samples.Web.Controllers.Api; - -public class PeopleController : UmbracoApiController -{ - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - - public PeopleController(IUmbracoContextAccessor umbracoContextAccessor) - { - _umbracoContextAccessor = umbracoContextAccessor; - } - - [HttpGet] - public ActionResult> GetAll() - { - if (_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? context) == false) - { - return this.Problem("unable to get content"); - } - - if (context.Content == null) - { - return this.Problem("Content Cache is null"); - } - - var personContentType = context.Content.GetContentType(Person.ModelTypeAlias); - Debug.Assert(context.Content.HasContent()); - var personNodes = (context.Content.GetAtRoot() - .First() - .FirstChild() - .Children() ?? Array.Empty()) - .Select(p => p.Name); - return personContentType == null - ? this.Problem("Person Content Type is null") - : Ok(personNodes); - } -} -``` - -UmbracoContext is registered with a scoped lifetime. See the [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#lifetime-and-registration-options) for more information. A service scope is created for each request, which means you can resolve an instance directly in a controller. diff --git a/10/umbraco-cms/reference/querying/umbracohelper.md b/10/umbraco-cms/reference/querying/umbracohelper.md deleted file mode 100644 index 5a3e1f56bf3..00000000000 --- a/10/umbraco-cms/reference/querying/umbracohelper.md +++ /dev/null @@ -1,189 +0,0 @@ ---- - - -meta.Title: "Umbraco Helper" -description: "Using the Umbraco Helper" ---- - -# UmbracoHelper - -UmbracoHelper is the unified way to work with published content/media on your website. You can use the UmbracoHelper to query/traverse Umbraco published data. - -UmbracoHelper also has a variety of helper methods that are useful when working in your views and controllers. - -## How to reference UmbracoHelper - -If you are using Views or Partial View Macros you can reference UmbracoHelper with the syntax: `@Umbraco` - -If you need an `UmbracoHelper` in your own controllers, you need to inject an instance. - -Example of getting `UmbracoHelper` in a controller: - -```C# -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Web.Common; -using Umbraco.Cms.Web.Common.Controllers; - -namespace UmbracoHelperDocs.Controllers -{ - [Route("customcontent/[action]")] - public class CustomContentController : Controller - { - private readonly UmbracoHelper _umbracoHelper; - - public CustomContentController(UmbracoHelper umbracoHelper) - => _umbracoHelper = umbracoHelper; - - public IActionResult GetHomeNodeName() - { - IPublishedContent rootNode = _umbracoHelper - .ContentAtRoot() - .FirstOrDefault(); - - if (rootNode is null) - { - return NotFound(); - } - - return Ok(rootNode.Name); - } - } -} -``` - -UmbracoHelper is registered with a scoped lifetime (see [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#lifetime-and-registration-options) for more information), as a service scope is created for each request you can resolve an instance directly in a controller. - -If you need to use an UmbracoHelper in a service with a singleton lifetime you would instead need to make use of the IUmbracoHelperAccessor interface to obtain a temporary reference to an instance. - -## IPublishedContent - -UmbracoHelper will expose all content in the form of `IPublishedContent`. To get a reference to the currently executing content item from the UmbracoHelper, use `UmbracoHelper.AssignedContentItem`. - -The samples below demonstrate using `UmbracoHelper` in Razor. Working with the `UmbracoHelper` will be the same in controllers, except for the fact that you must resolve it with `IUmbracoHelperAccessor` like shown above. - -## Working with Content - -### .Content(Guid id) - -Given a node ID, returns a `IPublishedContent` - -```csharp -@{ - var pageFromGui = Umbraco.Content(Guid.Parse("af22cb83-9bd4-454b-ab06-cc19ac8e983d")); -} - -

@pageFromGui.Value("propertyAlias")

- -@foreach (var child in pageFromGui.Children) -{ - @child.Name -} -``` - -### .ContentAtRoot() - -Returns a collection of `IPublishedContent` objects from the Content tree. - -```csharp -@* Get the children of the first content item found in the root *@ -@foreach (var child in Umbraco.ContentAtRoot().First().Children) -{ - @child.Name -} -``` - -### .ContentAtXPath(string xpath) - -Queries the cache for content matching a given XPath query and returns a collection of `IPublishedContent` objects. - -```csharp -@{ - var newsArticles = Umbraco.ContentAtXPath("//newsArticle"); - var bodyText = newsArticles.First().Value("bodyText"); -} -``` - -### .ContentSingleAtXPath(string xpath) - -Queries the cache for content matching a given XPath query and returns the first match as an `IPublishedContent` object. - -```csharp -@{ - var newsArticle = Umbraco.ContentSingleAtXPath("//newsArticle"); - var bodyText = newsArticle.Value("bodyText"); -} -``` - -## Working with Media - -### .Media(Guid id) - -Given a node ID, returns an `IPublishedContent` Media entity - -```csharp -@{ - var media = Umbraco.Media(Guid.Parse("ca4249ed-2b23-4337-b522-63cabe5587d1")); - var image = media.Url(); - var height = media.Value("umbracoHeight"); -} -``` - -### .MediaAtRoot() - -Returns a collection of `IPublishedContent` objects from the Media tree. - -```csharp -@foreach (var child in Umbraco.MediaAtRoot()) -{ - -} -``` - -## Working with Tags - -Previously the `UmbracoHelper` could be used to work with tags, this has been moved out of `UmbracoHelper` and is now available from `ITagQuery` which you can read more about in the [ITagQuery document](itagquery.md). - - -## Working with Members - -Previously the `UmbracoHelper` could be used to work with members, this has ben moved out of `UmbracoHelper` and is now available from `IMemberManager`, see [IMemberManager](imembermanager.md) for more information - -## Searching - -Previously the `UmbracoHelper` could be used to run queries on your content, this has been moved out of `UmbracoHelper` and is now available from `IPublishedContentQuery`, see [IPublishedContentQuery](ipublishedcontentquery.md) for more information. - -## Fetching Dictionary Values - -### .GetDictionaryValue(string key) - -Returns a dictionary value(`string`) for the key specified. - -```html -

@Umbraco.GetDictionaryValue("createdOn"): @Model.CreateDate

-``` - -Alternatively, you can also specify an `altText` which will be returned if the dictionary value is empty. - -```html -

@Umbraco.GetDictionaryValue("createdOn", "Date Created"): @Model.CreateDate

-``` - - -## Templating Helpers - -### .RenderMacro(string alias, object parameters) - -Renders a macro in the current page content, given the macro's alias, and parameters required by the macro. - -```csharp -@await Umbraco.RenderMacroAsync("navigation", new {root="1083", header="Hello"}) -``` - -### .RenderTemplateAsync(int contentId, int? altTemplateId) - -Renders a template asynchronously, as if a page with the given contentId was requested, optionally with an alternative template ID passed in. - -```csharp -@await Umbraco.RenderTemplate(1234) -``` diff --git a/10/umbraco-cms/reference/response-caching.md b/10/umbraco-cms/reference/response-caching.md deleted file mode 100644 index fcd94c5e52c..00000000000 --- a/10/umbraco-cms/reference/response-caching.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -versionFrom: 9.3.0 ---- - -# Response Caching - -Response caching reduces the number of requests a client or proxy makes to a web server. See the Microsoft documentation for details of [Response caching in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/response?view=aspnetcore-6.0) and how to implement the [Response Caching Middleware](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-6.0). - -## Modify the `Cache-Control` header for Static Files - -Example class to allow the modification of the `Cache-Control` header for static assets by file extension, but excluding Umbraco BackOffice assets. - -```csharp -using System.IO; -using System; -using System.Collections.Generic; - -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; -using Microsoft.AspNetCore.Http.Headers; -using Microsoft.Net.Http.Headers; - -using Umbraco.Cms.Core.Configuration.Models; -using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; - -namespace Umbraco.Docs.Samples.Web.Tutorials -{ - public class ConfigureStaticFileOptions : IConfigureOptions - { - // These are the extensions of the file types we want to cache (add and remove as you see fit) - private static readonly HashSet _cachedFileExtensions = new(StringComparer.OrdinalIgnoreCase) - { - ".ico", - ".css", - ".js", - ".svg", - ".woff2", - ".jpg" - }; - - private readonly string _backOfficePath; - - public ConfigureStaticFileOptions(IOptions globalSettings, IHostingEnvironment hostingEnvironment) - => _backOfficePath = globalSettings.Value.GetBackOfficePath(hostingEnvironment); - - public void Configure(StaticFileOptions options) - => options.OnPrepareResponse = ctx => - { - // Exclude Umbraco backoffice assets - if (ctx.Context.Request.Path.StartsWithSegments(_backOfficePath)) - { - return; - } - - // Set headers for specific file extensions - var fileExtension = Path.GetExtension(ctx.File.Name); - if (_cachedFileExtensions.Contains(fileExtension)) - { - ResponseHeaders headers = ctx.Context.Response.GetTypedHeaders(); - - // Update or set Cache-Control header - CacheControlHeaderValue cacheControl = headers.CacheControl ?? new CacheControlHeaderValue(); - cacheControl.Public = true; - cacheControl.MaxAge = TimeSpan.FromDays(365); - headers.CacheControl = cacheControl; - } - }; - } -} -``` - -Register the service in `Startup.cs` - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddTransient, ConfigureStaticFileOptions>(); -``` - -## Modify the `Cache-Control` header for ImageSharp.Web - -For setting `Cache-Control` max-age header for images processed by the ImageSharp middleware, you can set the `Umbraco:CMS:Imaging:Cache:BrowserMaxAge` setting. - -See the [Images Settings](configuration/imagingsettings.md) article for more information. - -## Add the `Cache-Control` header for rendering using the [ResponseCache attribute](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/response?view=aspnetcore-6.0#responsecache-attribute) - -For example using a custom [Default Controller](../implementation/default-routing/controller-selection.md#change-the-default-controllers) you can add the ResponseCache attribute to the `Index` method - -```csharp -public class DefaultController : RenderController -{ - public DefaultController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, compositeViewEngine, umbracoContextAccessor) - { - } - - [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] - public override IActionResult Index() - { - return CurrentTemplate(new ContentModel(CurrentPage)); - } -} -``` diff --git a/10/umbraco-cms/reference/routing/README.md b/10/umbraco-cms/reference/routing/README.md deleted file mode 100644 index fd7924bd2d3..00000000000 --- a/10/umbraco-cms/reference/routing/README.md +++ /dev/null @@ -1,41 +0,0 @@ ---- - -meta.Title: "Routing & Controllers Reference" -description: "All about Umbraco's routing pipeline & the types of Controllers used in Umbraco" ---- - -# Routing & Controllers - -All about Umbraco's routing pipeline & the types of Controllers used in Umbraco, how they work, and what they are used for. - -## [Request Pipeline](request-pipeline/) - -Explains how Umbraco builds its URLs and how the URLs are mapped back to content items. - -## [Routing Properties](routing-properties.md) - -Describes the Umbraco special/reserved Property Type aliases that can be used to directly manipulate Umbraco's default routing pipeline. These special Property Type aliases can be useful when creating an Umbraco website. - -## [Surface Controllers](surface-controllers/) - -What is a Surface Controller and how to use them? - -## [Umbraco API Controllers](umbraco-api-controllers/) - -What is an API Controller and how to use them? - -## [Custom Controllers (hijacking routes)](custom-controllers.md) - -Creating custom controllers to have 100% full control over how your pages are rendered. Also known as: Hijacking Umbraco Routes - -## [Custom Routes](custom-routes.md) - -How to specify your own custom MVC routes in your Umbraco application? - -## [Routes & Authentication](authorized.md) - -Routing requirements for authenticated controllers for both front-end and the backoffice. - -## [URL Tracking](url-tracking.md) - -Moving and renaming Umbraco documents will lead to URL redirects to be created. diff --git a/10/umbraco-cms/reference/routing/authorized.md b/10/umbraco-cms/reference/routing/authorized.md deleted file mode 100644 index d11d56f12e3..00000000000 --- a/10/umbraco-cms/reference/routing/authorized.md +++ /dev/null @@ -1,113 +0,0 @@ ---- - - -meta.Title: "Routing Requirements for Backoffice authentication" -description: "Requirements for authenticating requests for the backoffice" ---- - -# Backoffice authentication - -In order for Umbraco to authenticate a request for the backoffice, the routing needs to be specific. Any URL that routes to: - -> /umbraco/backoffice/* - -will be authenticated. If you have a controller that is not routed within the prefix, it will not be authenticated for backoffice use. - -You do not have to worry about routing if you are using `Umbraco.Cms.Web.BackOffice.Controllers.UmbracoAuthorizedApiController` (or any inherited controller) since these are auto routed. All implementations of `UmbracoAuthorizedApiController` (which includes `UmbracoAuthorizedJsonController`) are auto-routed with the default route: - -> `/umbraco/backoffice/api/{controller}/{action}` - -In the case that an Umbraco Api Controller is a 'Plugin Controller', then the route would be: - -> `/umbraco/backoffice/{pluginname}/{controller}/{action}` - -{% hint style="info" %} -The {area} specified by the [PluginController] attribute replaces the /api/ area for the route. -{% endhint %} - -## MVC controllers for the backoffice - -Depending on the type of controller used (MVC or WebAPI), the controller is not auto-routed. You will need to declare a custom route and register it with the Umbraco DI container to make it work. - -For more information on authenticated/authorized controllers & attributes see the [Controllers Documentation](../../implementation/controllers.md). - -## Defining a route - -Defining a route is done with the standard .NET Core MVC routing practices, however there is a handy extension method on the `IEndpointRouteBuilder` to help you. - -When creating custom routes you can either do it directly in the `Startup.cs` files, or with a pipeline filter in a composer which looks something like: - -```csharp -public class MyControllerComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.Services.Configure(options => - { - options.AddFilter(new UmbracoPipelineFilter(nameof(MyController)) - { - Endpoints = app => app.UseEndpoints(endpoints => - { - var globalSettings = app.ApplicationServices - .GetRequiredService>().Value; - var hostingEnvironment = app.ApplicationServices - .GetRequiredService(); - var backofficeArea = Constants.Web.Mvc.BackOfficePathSegment; - - var rootSegment = $"{globalSettings.GetUmbracoMvcArea(hostingEnvironment)}/{backofficeArea}"; - var areaName = "MyPackageName"; - endpoints.MapUmbracoRoute(rootSegment, areaName, areaName); - }) - }); - }); - } -} -``` - -The signature of `MapUmbracoRoute` is as follows - -```csharp -public static void MapUmbracoRoute( - this IEndpointRouteBuilder endpoints, - string rootSegment, - string areaName, - string? prefixPathSegment, - string defaultAction = "Index", - bool includeControllerNameInRoute = true, - object? constraints = null) -``` - -* The generic type argument is the contoller you wish to route, in this case `MyController`. -* `rootSegment` - The first part of the pattern, since this is an authorized controller it has to be `umbraco/backoffice`. -* `areaName` - The name of the area the controller should be routed through, an empty string signifies no area. -* `prefixPathSegment` - Prefix to be applied to the rootSegment, we know this from api controllers where the prefix is `api`, in this case since the controller is in an area we will also prefix the area name to the URL, so the final path pattern will be `umbraco/backoffice/mypackagename/{controllerName}/{action}/{id?}`. -* `defaultAction` - If this is not null or an empty string the request will automatically be routed to the specified action, so in this case `umbraco/backoffice/mypackagename/{controllerName}` will route to the index action. -* `includeControllerNameInRoute` - If this is false the controller name will be excluded from the route, so in this case the route would be `umbraco/backoffice/mypackagename/{action}/{id?}` if this was set to false. -* `constraints` - Any routing constraints passed to this will be used when mapping the route see [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-5.0#route-constraint-reference) for more information. - -Using the `MapUmbracoRoute` extension method is optional though, it's a neat helper to ensure controllers get routed in the same way. If your controller uses an area, like in this example, you need to specify this using the `Area` attribute. In this example the controller looks like this: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Web.Common.Controllers; - -namespace Umbraco.Cms.Web.UI.NetCore -{ - [Area("MyPackageName")] - public class MyController : UmbracoAuthorizedController - { - public IActionResult Index() - { - return Content("Hello from authorized controller"); - } - } -} -``` - - -{% hint style="info" %} -The route must be prefixed with the Umbraco path, which is configurable and resolved with `GetUmbracoMvcArea()` from `IGlobalSettings`. Then, it should be followed by "/backoffice" in order for Umbraco to check user authentication. -{% endhint %} - -### What about Surface Controllers? -Surface Controllers should not be used in the backoffice. Surface Controllers are not designed to work with the backoffice. They are not meant to be used there and will not be supported being used there. diff --git a/10/umbraco-cms/reference/routing/custom-controllers.md b/10/umbraco-cms/reference/routing/custom-controllers.md deleted file mode 100644 index f3c848f3ce5..00000000000 --- a/10/umbraco-cms/reference/routing/custom-controllers.md +++ /dev/null @@ -1,418 +0,0 @@ ---- - - -meta-title: Umbraco Route Hijacking -description: >- - Use a custom MVC controller to handle and control incoming requests for - content pages based on a specific Document Type, also called Route Hijacking. ---- - -# Custom MVC controllers (Umbraco Route Hijacking) - -_Use a custom controller to handle and control incoming requests for content pages based on a specific Document Type_ - -## What is Umbraco Route Hijacking? - -By default, all front end requests to an Umbraco site are auto-routed via the 'Index' action of a core Controller: `Umbraco.Cms.Web.Common.Controllers.RenderController`. This core controller handles the incoming request, builds the associated PublishedContent model, and passes this to the appropriate Umbraco Template/MVC View. - -It is however possible to implement a custom Controller to replace this default implementation to give complete control over this execution. - -For example: - -* To enrich the view model passed to the template with additional properties (from other published content items or outside Umbraco) -* To implement serverside paging -* To implement any custom/granular security -* To return alternative templates depending on some custom business logic - -This replacement of the default controller can be made 'globally' for all requests (see last example). It can also be by _'hijacking'_ requests for types of pages based on their specific Document Type following this controller naming convention: `[DocumentTypeAlias]Controller`. - -## Creating a custom controller - -### Example: Hijacking route requests to a 'product' page - -In the following example, imagine an Umbraco site with a set of 'product' pages created from a Document Type called 'Product Page' with an alias 'productPage'. - -Create a custom locally declared controller in the Umbraco web application project named 'ProductPageController'. - -Ensure that this controller inherits from the base controller `Umbraco.Cms.Web.Common.Controllers.RenderController`. - -eg: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; - -namespace My.Website -{ - public class ProductPageController : RenderController - { - public ProductPageController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - } - - public override IActionResult Index() - { - // you are in control here! - - // return a 'model' to the selected template/view for this page. - return CurrentTemplate(CurrentPage); - } - } -} -``` - -All requests to any 'product' pages in the site will be'hijacked' and routed through the custom ProductPageController. - -If you prefer to use an async controller your need to override both the sync and the async Index()-methods. This is done to disable the default behavior from the base controller. - -```csharp -public class ProductPageController : RenderController -{ - - [NonAction] - public sealed override IActionResult Index() => throw new NotImplementedException(); - public async Task Index(CancellationToken cancellationToken) - { - await SomethingAsync(cancellationToken); - return CurrentTemplate(CurrentPage); - } -} -``` - -This example shows the default behaviour that Umbraco's core RenderController provides. The 'Index' action of the controller is executed, and the CurrentTemplate helper sends the model containing the details of the published content item related to the request to the relevant template/view. - -## Routing via template - -A further convention is that if an action on the controller has a name that matches the template name, this action will be executed instead of the default 'Index' action. - -### Example: Hijacking route requests to a 'product' for an alternative 'AMP' template - -In this example, the Product Page Document Type has two templates 'ProductPage' and 'ProductAmpPage'. We can hijack and handle the requests to the two templates differently. - -Create the Controller as before: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; - - -namespace My.Website -{ - public class ProductPageController : RenderController - { - public ProductPageController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - } - - // Any request for the 'ProductAmpPage' template will be handled by this Action - public IActionResult ProductAmpPage() - { - // Create AMP specific content here... - return CurrentTemplate(CurrentPage); - } - - public override IActionResult Index() - { - // you are in control here! - - // return a 'model' to the selected template/view for this page. - return CurrentTemplate(CurrentPage); - } - } -} -``` - -#### How can a page be requested via two different templates? - -The page in Umbraco will have a single 'template' selected as it's default template, but it's possible to call this same page on a different template by adding `?altTemplate=othertemplatename` to the Url QueryString eg: - -`/products/superfancyproduct/?altTemplate=ProductAmpPage` - -### Summary - How the route hijacking convention works - -* Document Type name = controller name -* Template name = action name (if no action matches or is not specified - then the 'Index' action will be executed). -* Controller Inherits from `Umbraco.Cms.Web.Common.Controllers.RenderController` - -## Returning a view with a custom model - -The steps to achieve this will differ, depending if your template views are using IPublishedContent or Modelsbuilder generated Models. - -### Changing the @inherits directive of your template - -By default, your Umbraco Template will be based on the `ContentModel` that the default `RenderController` passes through to it. - -The default inherits statement: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -``` - -or if you are using modelsbuilder: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -``` - -`<>` contains a model generated for each document type to give strongly typed access to the Document Type properties in the template view. - -To use a specific custom view model, the `@inherits` directive will need to be updated to reference your custom model using the `Umbraco.Cms.Web.Common.Views.UmbracoViewPage` format where 'T' is the type of your custom model. - -So for example, if your custom model is of type 'MyProductViewModel' then your `@inherits` directive will look like: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -``` - -{% hint style="info" %} -Views will likely specify a master view to use as the common layout for the site html. When using a custom view model it's necessary to make sure this doesn't conflict with any implementation in the master layout view. Eg. if your master layout view is inheriting from a specific model `UmbracoViewPage` and using a property from SpecificModel that isn't available in your custom model an exception will be thrown. To avoid this you could: - -* Keep your Master layout view 'generically typed', eg. only have `@inherits UmbracoViewPage`, and use Model.Value syntax to access properties. or -* Break the dependency on `Umbraco.Cms.Core.Models` in your master layout by having it instead inherit from `Umbraco.Cms.Web.Common.Views.UmbracoViewPage`. This would be where ISomeInterface is implemented by all your models and contains the properties that the master layout view uses. or -* Ensure your custom models inherit from whichever class is used to strongly type the master layout view. -{% endhint %} - -In most cases you will need your custom model to build upon the underlying existing PublishedContent model for the page. This can be achieved by making your custom model inherit from a special base class called `PublishedContentWrapped`: - -```csharp -public class MyProductViewModel : PublishedContentWrapped -{ - // The PublishedContentWrapped accepts an IPublishedContent item as a constructor - public MyProductViewModel(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content, publishedValueFallback) - { - } - - // Custom properties here... - public int StockLevel { get; set; } - public IEnumerable ProductDistributors { get; set; } -} -``` - -`PublishedContentWrapped` will take care of populating all the usual underlying Umbraco properties and means the `@Model.` syntax will continue to work in the layouts used by your template. - -Using Modelsbuilder you will find that all the generated models have a constructor that takes an IPublishedContent item in a similar way: - -```csharp -public class MyProductViewModel : ProductPage -{ - // The ProductPage model accepts an IPublishedContent item as a constructor - public MyProductViewModel(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content, publishedValueFallback) - { - } - - // Custom properties here... - public int StockLevel { get; set; } - public IEnumerable ProductDistributors { get; set; } -} -``` - -{% hint style="info" %} -The models generated by Modelsbuilder are created as partial classes so it's possible to extend them by adding your own partial classes with matching signature. -{% endhint %} - -We can now populate our custom view model in our controller and use the values from the custom model in our template view: - -```csharp -using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; -using My.Website.Models; - - -namespace My.Website -{ - public class ProductPageController : RenderController - { - private readonly IVariationContextAccessor _variationContextAccessor; - private readonly ServiceContext _serviceContext; - public ProductPageController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor, IVariationContextAccessor variationContextAccessor, ServiceContext context) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - _variationContextAccessor = variationContextAccessor; - _serviceContext = context; - } - - public override IActionResult Index() - { - - // you are in control here! - // create our ViewModel based on the PublishedContent of the current request: - // set our custom properties - var productViewModel = new MyProductViewModel(CurrentPage, new PublishedValueFallback(_serviceContext, _variationContextAccessor)) - { - StockLevel = 4, - ProductDistributors = new List() - }; - - - // return our custom ViewModel - return CurrentTemplate(productViewModel); - - } - } - -} -``` - -and in our template - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@{ -Layout = "Master"; -} -

@Model.Name

- -@(Model.Value("productDescription")) -// or using Modelsbuilder -@Model.ProductDescription - -
-
Stock Level
-
@Model.StockLevel
-
Distributors
-@foreach (var distributor in Model.Distributors){ -
@distributor.Name
-} -``` - -## Processing QueryString values in the controller - -You can also pass values directly into the controller action using the query string. - -``` -?page=1&andanotherthing=umbraco -``` - -The values in the querystring will be bound to the matching parameters defined in the controller's action: - -```csharp -public class ProductListingPageController : Umbraco.Cms.Web.Common.Controllers.RenderController -{ - //notice how we are no longer overriding the Index action because the signature is now different to the base signature. - [HttpGet] - public IActionResult Index([FromQuery(Name = "page")] int page, [FromQuery(Name = "andAnotherThing")] string andAnotherThing) - { - var products = _madeUpProductService.GetProductsByPage(page); - var productListingViewModel = new ProductListingViewModel(CurrentPage, new PublishedValueFallback(_serviceContext, _variationContextAccessor)); - productListingViewModel.Products = products; - productListViewModel.Thing = andAnotherThing; - - return CurrentTemplate(productListViewModel); - } -} -``` - -## Controller Injection - -Injecting services into your controller constructors is possible with Umbraco's underlying dependency injection implementation. See [Services and Helpers](../../implementation/services/#custom-services-and-helpers) for more info on this. - -For example: - -```csharp - public class ProductListingPageController : RenderController - { - private readonly IMadeUpProductService _madeUpProductService; - public ProductListingPageController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor, IMadeUpProductService madeUpProductService) - { - _madeUpProductService = madeUpProductService; - } - - public override IActionResult Index() - { - var products = _madeUpProductService.GetProductsByPage(page); - ... - } -``` - -To wire up a concrete instance of IMadeUpProductService, use a composer: - -```csharp - using Umbraco.Cms.Core.Composing; - using Umbraco.Cms.Core.DependencyInjection; - using Umbraco.Extensions; - - namespace MyWebsite.Composers - { - public class RegisterSuperSiteServiceComposer : IUserComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - - } - } - } -``` - -See [Composing](../../implementation/composing.md) for further information. - -## Replace Umbraco's default `RenderController` - -You can replace Umbraco's default implementation of RenderController with your own custom controller for all MVC requests. This is possible by assigning your own default controller type in the Umbraco setup during initialization. - -You can achieve this by updating the options for `UmbracoRenderingDefaultsOptions` in the `ConfigureServices` method in the `Startup.cs` class. - -First of all you have to create your own controller. Your custom implementation of RenderController should either inherit from the core `RenderController` as in the examples above or implement the `IRenderController` interface. - -Implement the `IRenderController`: - -```csharp -public class MyRenderController : IRenderController -{ - public IActionResult Index() - { - return new OkObjectResult("Hello from your custom Render Controller"); - } -} -``` - -Or inherit from `RenderController` - -```csharp -public class MyRenderController : RenderController -{ - public MyRenderController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) - : base(logger, compositeViewEngine, umbracoContextAccessor) - { - } - - public override IActionResult Index() - { - // Add some custom logic here. - return CurrentTemplate(CurrentPage); - } -} -``` - -The last step is to configure Umbraco to use your implementation. You can do that in the `ConfigureServices` method in the `Startup.cs` class. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .Build(); - - // Configure Umbraco Render Controller Type - services.Configure(c => - { - c.DefaultControllerType = typeof(MyRenderController); - }); -} -``` diff --git a/10/umbraco-cms/reference/routing/custom-routes.md b/10/umbraco-cms/reference/routing/custom-routes.md deleted file mode 100644 index 80d0f00130f..00000000000 --- a/10/umbraco-cms/reference/routing/custom-routes.md +++ /dev/null @@ -1,522 +0,0 @@ ---- - - -meta.Title: Custom Umbraco Routes -description: >- - Setting up your own controllers and routes that exist alongside the Umbraco - pipeline ---- - -# Custom MVC Routes - -_Documentation about how to setup your own custom controllers and routes that need to exist alongside the Umbraco pipeline_ - -## Where to put your routing logic? - -There's two places you can specify your routing, depending on whether it's in the context of a package, or your own site. If it's your own site you can do it in the `Configure` method of `Startup.cs` within the `WithEndpoints` method call like so: - -```csharp -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseUmbraco() - .WithMiddleware(u => - { - u.WithBackOffice(); - u.WithWebsite(); - }) - .WithEndpoints(u => - { - // This is where to put the custom routing - - u.UseInstallerEndpoints(); - u.UseBackOfficeEndpoints(); - u.UseWebsiteEndpoints(); - }); -} -``` - -If you're creating a package you won't have access to the `Startup.cs` file, so instead you must use a composer, for an example of this, see the example below. - -## User defined routes - -Umbraco doesn't interfere with any user defined routes that you wish to have. Your custom routes to your own custom controllers will work perfectly and seamlessly alongside Umbraco's routes. - -## Custom routes within the Umbraco pipeline - -For a request to be considered executing in an Umbraco context, and therefore the Umbraco pipeline, it needs to have an HTTP request feature with the type `UmbracoRouteValues`, all the information required for Umbraco to handle the request is stored there. The question is now, how do we add this request feature? There's three possibilities: - -1. Do it completely manually - This requires that you have a custom route, controller, even middleware, and manually assign the `UmbracoRouteValues` as an HTTP request feature, however you see fit. To create an `UmbracoRouteValues` object generally requires: `IUmbracoContextAccessor` (to access the `CleanedUmbracoUrl`), `IPublishedRouter` (to create the `IPublishedRequestBuilder`), `IPublishedRequestBuilder` (to set the published content and to build the `IPublishedRequest`), `IPublishedRequest` to assign to the `UmbracoRouteValues`. As you can see this is quite a lot of work, but luckily there's some much easier ways. -2. Route a custom controller that implements the `IVirtualPageController` interface, assigning the `UmbracoRouteValues` to the HTTP requests will then be taken care of for you. -3. Route a custom controller with conventional routing, using the typical call to `endpoints.MapControllerRoute`, and then call `.ForUmbracoPage()` with an action for finding content on what `MapControllerRoute` returns, now `UmbracoRouteValues` will automatically be applied to any request to that controller. - -Don't fret if this all seems a bit overwhelming, we'll be going through an example of the last two options. - -### Custom route with IVirtualPageController - -As mentioned, with this approach we need to implement the `IVirtualPageController` interface, this interface only has one method `FindContent` which accepts an `ActionExecutingContext`: - -```csharp -IPublishedContent FindContent(ActionExecutingContext actionExecutingContext); -``` - -It can also be helpful to inherit from the `UmbracoPageController` since this includes some useful helper methods such as `CurrentPage`, do however note that it is _not_ possible to inherit from `RenderController` when doing custom routes like this. - -Let's create a shop controller, with an Index action showing all our products, and an Product action which will show some custom data about the product that could exists outside Umbraco. A common approach in a scenario like this is to have a "real" Umbraco node as a starting point. In this example we're going to use an empty "Products" document type to act as a list view, and "Product" document type which only contains an SKU. We also need some content based on those document types, a "Products" content node, which contains two product nodes, each with their own SKU. - -After that bit of setup we can go ahead and create our shop controller which inherits from `UmbracoPageController` and implements `IVirtualPageController`, it'll look like this: - -```csharp -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Web.Common.Controllers; - -namespace RoutingDocs.Controllers -{ - public class ShopController : UmbracoPageController, IVirtualPageController - { - public ShopController( - ILogger logger, - ICompositeViewEngine compositeViewEngine) - : base(logger, compositeViewEngine) - { } - - public IPublishedContent FindContent(ActionExecutingContext actionExecutingContext) - { } - } -} -``` - -Now you'll see that `FindContent` is complaining because we're not returning anything yet, but let's start by creating our to action methods that `FindContent` will find content for. - -First off we have the Index method: - -```csharp -[HttpGet] -public IActionResult Index() -{ - // CurrentPage (IPublishedContent) will be the content returned - // from the FindContent method. - - // return the view with the IPublishedContent - return View(CurrentPage); -} -``` - -This is a fairly straightforward method, we return the view with the content found by the `FindContent` method, which can then be used to list all the children in the view with `Model.Children` - -Next we have our Product method: - -```csharp -[HttpGet] -public IActionResult Product(string id) -{ - // CurrentPage (IPublishedContent) will be the content returned - // from the FindContent method. - - // One example of using a custom route would be to include additional - // model information based on external services. For example, if - // we wanted to return the stores the product is available in from - // a custom data store. - var dbProduct = DbContext.Products.GetBySku(id); - var shopModel = new Product(CurrentPage) - { - Sku = id, - AvailableStores = dbProduct.AvailableStores - }; - - return View(shopModel); -} -``` - -Here, we get some extra data from a different source. In this case, a `DbContext`, but this can be anything you want, using the ID we get from the route values. We use this extra data to create a custom model, which includes the available stores, which we then render the view with. - -It's important to note that this custom model must implement `IPublishedContent`, to do this we inherit from the `ContentModel` class, in this case our model looks like this: - -```csharp -public class Product : ContentModel -{ - public Product(IPublishedContent content) : base(content) - { - } - - public string Sku { get; set; } - public IEnumerable AvailableStores { get; set; } -} -``` - -What's great about this is that we can use this model as a type argument when inheriting from `UmbracoViewPage` in our model like so: - -```html -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -``` - -Which makes the model typed, so we can access the available stores like so: - -```html -
    - @foreach (var store in Model.AvailableStores) - { -
  • @store
  • - } -
-``` - -But let's get back to our controller, the last thing we need now is to implement `FindContent` method so we can find content for our actions and serve it to them. First we need to be able to get our content, and properties, so we need to inject `IUmbracoContextAccessor` and `IPublishedValueFallback` and save them to some fields like so: - -```csharp -private readonly IUmbracoContextAccessor _umbracoContextAccessor; -private readonly IPublishedValueFallback _publishedValueFallback; - -public ShopController( - ILogger logger, - ICompositeViewEngine compositeViewEngine, - IUmbracoContextAccessor umbracoContextAccessor, - IPublishedValueFallback publishedValueFallback) - : base(logger, compositeViewEngine) -{ - _umbracoContextAccessor = umbracoContextAccessor; - _publishedValueFallback = publishedValueFallback; -} -``` - -Now that we have our dependencies, and our action methods, we're finally ready to implement the `FindContent` method: - -```csharp -public IPublishedContent FindContent(ActionExecutingContext actionExecutingContext) -{ - if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) - { - var productRoot = umbracoContext.Content.GetById(2074); - if (productRoot!=null) - { - - if (actionExecutingContext.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) - { - // Check which action is executing - switch (controllerActionDescriptor.ActionName) - { - case nameof(Index): - return productRoot; - - case nameof(Product): - // Get the SKU/Id from the route values - if (actionExecutingContext.ActionArguments.TryGetValue("id", out var sku)) - { - return productRoot - .Children - .FirstOrDefault(c => c.Value(_publishedValueFallback, "sku") == sku.ToString()); - } - else - { - return productRoot; - } - } - } - - return productRoot; - } - } - - return null; -} -``` - -Start by retrieving the product root using the `UmbracoContext` to obtain it based on its ID. Next, let's figure out what action is being requested. To do this, cast the `actionExecutingContext.ActionDescriptor` to a `ControllerActionDescriptor` and use its `ActionName` property. If the action name is index, it returns the product root. If it's a product, we get the SKU from the route value `id` and find the matching child node. - -Now there's only one last thing to do, we need to register our shop controller, if you're creating a controller for your own site you can do it in the `Configure` method of `Startup.cs` like so: - -```csharp -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseUmbraco() - .WithMiddleware(u => - { - u.WithBackOffice(); - u.WithWebsite(); - }) - .WithEndpoints(u => - { - u.EndpointRouteBuilder.MapControllerRoute( - "Shop Controller", - "/shop/{action}/{id?}", - new {Controller = "Shop", Action = "Index"}); - - u.UseInstallerEndpoints(); - u.UseBackOfficeEndpoints(); - u.UseWebsiteEndpoints(); - }); -} -``` - -There's nothing Umbraco-specific about the controller routing; it's using the default `MapController` route of the `EndpointRouteBuilder`. Give the mapping a name, a pattern for the controller, and some default values, so if no action is specified, it will default to `Index`. - -If you're creating a package you won't have access to the `Startup.cs`, so instead you can use a composer with an `UmbracoPipelineFilter` like so: - -```csharp -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Web.Common.ApplicationBuilder; - -namespace RoutingDocs.Controllers -{ - public class ShopControllerComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.Configure(options => - { - options.AddFilter(new UmbracoPipelineFilter(nameof(ShopController)) - { - Endpoints = app => app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - "Shop Controller", - "/shop/{action}/{id?}", - new {Controller = "Shop", Action = "Index"}); - }) - }); - }); - } - } -} -``` - -With that we have our controller with a custom route within an Umbraco context. - -#### Client-Side Requests - -If the endpoint of your custom route is considered a client-side request e.g. **/sitemap.xml**, you will need to make a few changes to get this to work. - -Define your route as before, specifying the correct client type route: - -```csharp -.WithEndpoints(u => -{ - u.EndpointRouteBuilder.MapControllerRoute("Sitemap Xml", "/sitemap.xml", - new { Controller = "SitemapXml", Action = "Index" }); -}); -``` - -You will need to configure your route request options within your **Startup.cs** class. For single routes: - -```csharp -services.Configure(options => -{ - options.HandleAsServerSideRequest = httpRequest => httpRequest.Path.StartsWithSegments("/sitemap.xml"); -}); -``` - -Or it can handle multiple routes: - -```csharp -services.Configure(options => -{ - string[] allowList = new[] {"/sitemap.xml", ...}; - options.HandleAsServerSideRequest = httpRequest => - { - foreach (string route in allowList) - { - if (httpRequest.Path.StartsWithSegments(route)) - { - return true; - } - } - - return false; - }; -}); -``` - -In your **FindContent** method you should still be able to access and use **IUmbracoContextAccessor** through standard DI: - -``` -public IPublishedContent? FindContent(ActionExecutingContext actionExecutingContext) -{ - IUmbracoContext context = _umbracoContextAccessor.GetRequiredUmbracoContext(); - IPublishedContent? content = context.Content?.GetAtRoot().FirstOrDefault(); - - return content; -} -``` - -#### Attribute routing with IVirtualPageController - -One of the benefits of the `IVirtualPageController` is that it allows you to use attribute routing. If you wish to use attribute routing you must use an `IVirtualPageController` and decorate your controller and/or actions with the `Route` attribute. If we want to convert our above example into using attribute routing we must first add the attributes to our actions: - -```csharp -[Route("[controller]")] -[Route("[controller]/[action]")] -[HttpGet] -public IActionResult Index() -``` - -```csharp -[Route("[controller]/[action]/{id?}")] -[HttpGet] -public IActionResult Product(string id) -``` - -Now all we need to do is change our routing to use `EndpointRouteBuilder.MapControllers();` instead of adding a specific route. - -```csharp -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) -{ - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseUmbraco() - .WithMiddleware(u => - { - u.WithBackOffice(); - u.WithWebsite(); - }) - .WithEndpoints(u => - { - u.EndpointRouteBuilder.MapControllers(); - - u.UseInstallerEndpoints(); - u.UseBackOfficeEndpoints(); - u.UseWebsiteEndpoints(); - }); -} -``` - -This will give us routing that's similar to what we have in the other example. It's worth noting that there's no defaults when using attribute routing, so to allow our index action to be accessed through both `/shop` and `/shop/index`, we add two attributes, specifying both routes individually. - -### Custom route with ForUmbracoPage - -Making a custom route within the Umbraco context using `ForUmbracoPage` is quite similar to using `IVirtualPageController`. The main difference is that with `ForUmbracoPage` we no longer find the content from within the controller, instead we assign the `FindContent` method when routing the controller. One important thing about `ForUmbracoPage` is that attribute routing is _not_ available, so to make our example from above work with `ForUmbracoPage`, we want to remove any attribute routing, and no longer implement `IVirtualPageController`, so we'll also remove the `FindContent` method, our controller will then end up looking like this: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using RoutingDocs.Models; -using RoutingDocs.Persistence; -using Umbraco.Cms.Web.Common.Controllers; - -namespace RoutingDocs.Controllers -{ - public class ShopController : UmbracoPageController - { - public ShopController( - ILogger logger, - ICompositeViewEngine compositeViewEngine) - : base(logger, compositeViewEngine) - { } - - [HttpGet] - public IActionResult Index() - { - // CurrentPage (IPublishedContent) will be the content returned - // from the FindContent method. - - // return the view with the IPublishedContent - return View(CurrentPage); - } - - [HttpGet] - public IActionResult Product(string id) - { - // CurrentPage (IPublishedContent) will be the content returned - // from the FindContent method. - - // One example of using a custom route would be to include additional - // model information based on external services. For example, if - // we wanted to return the stores the product is available in from - // a custom data store. - var dbProduct = DbContext.Products.GetBySku(id); - var shopModel = new Product(CurrentPage) - { - Sku = id, - AvailableStores = dbProduct.AvailableStores - }; - - return View(shopModel); - } - } -} -``` - -As you can see we still inherit from `UmbracoPageController` to get access to the helper method `CurrentPage`, but the rest is a normal controller. - -The Umbraco magic will now instead happen where we route the controller, here we will pass a `Func` delegate to the `ForUmbracoPage` method, this delegate is then responsible for finding the content, for instance using a composer with the same logic as in the `IVirtualPageController` it will look like this: - -```csharp - public class ShopControllerComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.Services.Configure(options => - { - options.AddFilter(new UmbracoPipelineFilter(nameof(ShopController)) - { - Endpoints = app => app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - "Shop Controller", - "/shop/{action}/{id?}", - new {Controller = "Shop", Action = "Index"}) - .ForUmbracoPage(FindContent); // Here we register our FindContent method - }) - }); - }); - } - - private IPublishedContent FindContent(ActionExecutingContext actionExecutingContext) - { - // Resolve services from the container - var umbracoContextAccessor = actionExecutingContext.HttpContext.RequestServices - .GetRequiredService(); - var publishedValueFallback = actionExecutingContext.HttpContext.RequestServices - .GetRequiredService(); - - var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); - var productRoot = umbracoContext.Content.GetById(2074); - - if (actionExecutingContext.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) - { - // Check which action is executing - switch (controllerActionDescriptor.ActionName) - { - case nameof(ShopController.Index): - return productRoot; - - case nameof(ShopController.Product): - // Get the SKU/Id from the route values - if (actionExecutingContext.ActionArguments.TryGetValue("id", out var sku)) - { - return productRoot - .Children - .FirstOrDefault(c => c.Value(publishedValueFallback, "sku") == sku.ToString()); - } - else - { - return productRoot; - } - } - } - return productRoot; - } -} -``` - -The `Compose` method of our composer is much the same as any other normal routing, with one difference we call `ForUmbracoPage` on the `MapControllerRoute` where we pass in our `FindContent` method. The `FindContent` method is also largely the same as it was in the controller in the `IVirtualPageController` example, with one important difference. Since we can no longer inject our required service into the constructor, we instead request them using `actionExecutingContext.HttpContext.RequestServices.GetRequiredService`. It's important to note here that you should _not_ save the `HttpContext` or the `IServiceProvider` you get from the `actionExecutingContext` to a field or property on the class since these will be specific for each request. - -With this we have a custom routed controller within the Umbraco pipeline, if you navigate to `/shop` or `/shop/product/` you will see the controllers actions being called with the content found in `FindContent` diff --git a/10/umbraco-cms/reference/routing/iisrewriterules.md b/10/umbraco-cms/reference/routing/iisrewriterules.md deleted file mode 100644 index 3a48bc72f5a..00000000000 --- a/10/umbraco-cms/reference/routing/iisrewriterules.md +++ /dev/null @@ -1,188 +0,0 @@ -# URL Rewrites in Umbraco - -With the release of Umbraco 9 and the change of the underlying web framework that is decoupled from the webserver, the way that you configure rewrites has changed as well. - -Instead of the URL Rewriting extension in IIS you can use the [URL Rewriting Middleware in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-5.0), which needs to be added to your project startup code first. - -{% hint style="info" %} -If you are running Umbraco 9 on IIS you can still add a `web.config` file to configure IIS features such as URL rewrites. -{% endhint %} - -## When to use the URL Rewriting Middleware - -Make sure to check the official [URL Rewriting Middleware in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-5.0#when-to-use-url-rewriting-middleware) documentation for more information about when you should or should not use the URL Rewriting Middleware. - -## Using the URL Rewriting Middleware - -To use rewrites with Umbraco 9 you have to register the middleware in your `Startup.cs` by using the [`UseRewriter`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.rewritebuilderextensions.userewriter?view=aspnetcore-5.0) extension method and then configure the rewrite options. - -### Example - -* Create an `IISUrlRewrite.xml` file in the root of your project (next to your `Startup.cs` file) containing: - -```xml - - - - - - - - - - - - - - -``` - -* In the `Startup.cs` file you can add the URL Rewriting Middleware just before the call to `app.UseUmbraco()` and use [`AddIISUrlRewrite`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.rewrite.iisurlrewriteoptionsextensions.addiisurlrewrite?view=aspnetcore-5.0)) to add the rewrite rules from the XML file: - -```csharp -using Microsoft.AspNetCore.Rewrite; - -var rewriteOptions = new RewriteOptions() - .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml"); - -app.UseRewriter(rewriteOptions); - -// This line is needed for the rewrites to take effect. -app.UseStaticFiles(); -``` - -{% hint style="info" %} -On Linux, make sure to place the `app.UseStaticFiles()` after the `app.UseUmbraco()` statements for the redirect to work as intended. -{% endhint %} - -* In your csproj file add the XML file to a new item group and set `CopyToOutputDirectory` to `Always`: - -```xml - - - Always - - -``` - -{% hint style="info" %} -On Umbraco Cloud the item group needs to be set to `Always` for the file to be published to your deployed site. -{% endhint %} - -## Rewrite rule shortcuts - -`RewriteOptions` has a number of "shortcut" methods to implement commonly used rewrites including: - -* `AddRedirectToNonWww()` -* `AddRedirectToWww()` -* `AddRedirectToNonWwwPermanent()` -* `AddRedirectToWwwPermanent()` -* `AddRedirectToHttps()` - -For more details and other examples, take a look at the [URL Rewriting Middleware in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting) and [RewriteOptions Class](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.rewrite.rewriteoptions) documentation. - -## Examples of rewrite rules - -### External Resources - -If you are looking for additional inspiration or examples for creating IIS Rewrite rules, these external resources are a great starting point: - -* A great site showing 10 handy IIS Rewrite rules: [URL rewriting tips and tricks](https://ruslany.net/2009/04/10-url-rewriting-tips-and-tricks/) -* Another site showing some handy examples of IIS Rewrite rules: [Some useful IIS rewrite rules](https://odetocode.com/blogs/scott/archive/2014/03/27/some-useful-iis-rewrite-rules.aspx) -* If you needed to a lot of static rewrites using rewrite maps: [Rule with rewrite map rule template](https://www.iis.net/learn/extensions/url-rewrite-module/rule-with-rewrite-map-rule-template) - -### Example: Remove a Trailing Slash - -The following rule removes any trailing slashes from the URL. - -```xml - - - - - - - - - -``` - -Ensure Umbraco does not add a trailing slash by setting `AddTrailingSlash` to `false` in your [RequestHandler settings](../configuration/requesthandlersettings.md). - -### Example: Enforce HTTPS - -The following rule ensures your site only runs on HTTPS: - -```xml - - - - - - - - -``` - -### Example: Redirect Non-www to www - -The following rule redirects traffic from non-www to www (excluding the Umbraco Cloud project hostname): - -```xml - - - - - - - - - -``` - -### Example: Remove the .aspx Extension - -The following rule redirects `.aspx` URLs to their extensionless counterparts. - -```xml - - - - - - - - - - - - - - - - - -``` - -### Example: Custom Rewrite Rules for Umbraco Cloud - -An example configuration to help ensure your custom rules integrate properly: - -```xml - - - - - - - - - - - - -``` - -{% hint style="info" %} -If you use **Umbraco Cloud**, check the [Rewrite Rules](https://docs.umbraco.com/umbraco-cloud/set-up/project-settings/manage-hostnames/rewrites-on-cloud) article. -{% endhint %} diff --git a/10/umbraco-cms/reference/routing/request-pipeline/README.md b/10/umbraco-cms/reference/routing/request-pipeline/README.md deleted file mode 100644 index 56cb7c10868..00000000000 --- a/10/umbraco-cms/reference/routing/request-pipeline/README.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -meta.Title: Routing in Umbraco -description: What the Umbraco Request Pipeline is ---- - -# Routing in Umbraco - -_This section describes what the Umbraco Request Pipeline is. It explains how Umbraco matches a document to a given request and how it generates a URL for a document._ - -## Request pipeline - -### What is the pipeline - -The request pipeline is the process of building up the URL for a node and resolving a request to a specified node. It ensures that the right content is sent back. - -![what is the pipeline](images/what-is-the-pipeline.png) - -### Outbound vs Inbound - -The pipeline works bidirectional: [**inbound**](inbound-pipeline.md) and [**outbound**](outbound-pipeline.md). - -[**Outbound**](outbound-pipeline.md) is the process of building up a URL for a requested node. [**Inbound**](inbound-pipeline.md) is every request received by the web server and handled by Umbraco. - -### Customizing the pipeline - -This section will describe the components that you can use to modify Umbraco's request pipeline: [**IContentFinder**](icontentfinder.md) & `IUrlProvider` diff --git a/10/umbraco-cms/reference/routing/request-pipeline/document/TheUmbracoRequestPipeline.pdf b/10/umbraco-cms/reference/routing/request-pipeline/document/TheUmbracoRequestPipeline.pdf deleted file mode 100644 index 44fdfa7b829..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/document/TheUmbracoRequestPipeline.pdf and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/find-publishedcontent-and-template.md b/10/umbraco-cms/reference/routing/request-pipeline/find-publishedcontent-and-template.md deleted file mode 100644 index 26592f9f0d3..00000000000 --- a/10/umbraco-cms/reference/routing/request-pipeline/find-publishedcontent-and-template.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -needsV8Update: 'true' ---- - -# FindPublishedContentAndTemplate() - -The followed method is called on the "PublishedContentRequest.PrepareRequest()" method: `FindPublishedContentAndTemplate()`. We discuss shortly what this method is doing: - -1. FindPublishedContent () -2. Handles redirects -3. HandlePublishedContent() -4. FindTemplate() -5. FollowExternalRedirect() -6. HandleWildcardDomains() - -#### HandlePublishedContent - -* No content? -* Run the LastChanceFinder -* Is an IContentFinder, resolved by ContentLastChanceFinderResolver -* By default, is null (= ugly 404) -* Follow internal redirects -* Take care of infinite loops -* Ensure user has access to published content -* Else redirect to login or access denied published content -* Loop while there is no content -* Take care of infinite loops - -#### FindTemplate - -* Use altTemplate if -* Initial content -* Internal redirect content, and InternalRedirectPreservesTemplate is true -* No alternate template? -* Use the current template if one has already been selected -* Else use the template specified for the content, if any -* Alternate template? - * Use the alternate template, if any - * Else use what’s already there: a template, else none -* Alternate template is used only if displaying the intended content - * Except for internal redirects - * If you enable InternalRedirectPreservesTemplate - * Which is false by default -* Alternate template replaces whatever template the finder might have set - * ContentFinderByNiceUrlAndTemplate - * /path/to/page/template1?altTemplate=template2  template2 -* Alternate template does not falls back to the specified template for the content - * /path/to/page?altTemplate=missing  no template - * Even if the page has a template -* But preserves whatever template the finder might have set - * /path/to/page/template1?altTemplate=missing  template1 - -#### FollowExternalRedirect() - -* Content.GetPropertyValue("umbracoRedirect") -* If it’s there, sets the published content request to redirect to the content -* Will trigger an external (browser) redirect - -#### HandleWildcardDomains() - -![](images/culture-and-hostnames.png) - -* Finds the deepest wildcard domain between -* Domain root (or top) -* Request’s published content -* If found, updates the request’s culture accordingly - -This implements separation between hostnames and cultures diff --git a/10/umbraco-cms/reference/routing/request-pipeline/icontentfinder.md b/10/umbraco-cms/reference/routing/request-pipeline/icontentfinder.md deleted file mode 100644 index bbd57dfc856..00000000000 --- a/10/umbraco-cms/reference/routing/request-pipeline/icontentfinder.md +++ /dev/null @@ -1,223 +0,0 @@ ---- - - -meta.Title: Creating content finders -description: Information about creating your own content finders ---- - -# IContentFinder - -To create a custom content finder, with custom logic to find an Umbraco document based on a request, implement the IContentFinder interface: - -```csharp -public interface IContentFinder -{ - Task TryFindContent(IPublishedRequestBuilder contentRequest); -} -``` - -and use either an Umbraco builder extension, or a composer to add it to it to the `ContentFindersCollection`. - -Umbraco runs all content finders in the collection 'in order', until one of the IContentFinders returns true. Once this occurs, the request is then handled by that finder, and no further IContentFinders are executed. Therefore the order in which ContentFinders are added to the ContentFinderCollection is important. - -The ContentFinder can set the PublishedContent item for the request, or template or even execute a redirect. - -## Example - -This IContentFinders will find a document with id 1234, when the Url begins with /woot. - -```csharp -public class MyContentFinder : IContentFinder -{ - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - - public MyContentFinder(IUmbracoContextAccessor umbracoContextAccessor) - { - _umbracoContextAccessor = umbracoContextAccessor; - } - - public Task TryFindContent(IPublishedRequestBuilder contentRequest) - { - var path = contentRequest.Uri.GetAbsolutePathDecoded(); - if (path.StartsWith("/woot") is false) - { - return Task.FromResult(false); // Not found - } - - if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) - { - return Task.FromResult(false); - } - - // Have we got a node with ID 1234 - var content = umbracoContext.Content.GetById(1234); - if (content is null) - { - // If not found, let another IContentFinder in the collection try. - return Task.FromResult(false); - } - - // If content is found, then render that node - contentRequest.SetPublishedContent(content); - return Task.FromResult(true); - } -} -``` - -### Adding and removing IContentFinders - -You either use an extension on the Umbraco builder or, a composer to access the `ContentFinderCollection` to add and remove specific `ContentFinders` - -#### Umbraco builder extension - -First create the extension method: - -``` -using RoutingDocs.ContentFinders; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Routing; - -namespace RoutingDocs.Extensions -{ - public static class UmbracoBuilderExtensions - { - public static IUmbracoBuilder AddMyCustomContentFinders(this IUmbracoBuilder builder) - { - // Add our custom content finder just before the core ContentFinderByUrl - builder.ContentFinders().InsertBefore(); - // You can also remove content finders, this is not required here though, since our finder runs before the url one - builder.ContentFinders().Remove(); - // You use Append to add to the end of the collection - builder.ContentFinders().Append(); - // or Insert for a specific position in the collection - builder.ContentFinders().Insert(3); - return builder; - } - } -} -``` - -Then invoke it in `ConfigureServices` in the `Startup.cs` file: - -``` -public void ConfigureServices(IServiceCollection services) -{ -#pragma warning disable IDE0022 // Use expression body for methods - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddMyCustomContentFinders() - .Build(); -#pragma warning restore IDE0022 // Use expression body for methods -} -``` - -#### Composer - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Routing; - -namespace RoutingDocs.ContentFinders -{ - public class UpdateContentFindersComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Add our custom content finder just before the core ContentFinderByUrl - builder.ContentFinders().InsertBefore(); - // You can also remove content finders, this is not required here though, since our finder runs before the url one - builder.ContentFinders().Remove(); - // You use Append to add to the end of the collection - builder.ContentFinders().Append(); - // or Insert for a specific position in the collection - builder.ContentFinders().Insert(3); - } - } -} -``` - -## NotFoundHandlers - -To set your own 404 finder create an IContentLastChanceFinder and set it as the ContentLastChanceFinder. (perhaps you have a multilingual site and need to find the appropriate 404 page in the correct language) - -A `IContentLastChanceFinder` will always return a 404 status code. This example creates a new implementation of the `IContentLastChanceFinder` and gets the 404 page for the current language of the request. - -```csharp -using System.Linq; -using System.Threading.Tasks; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; - -namespace RoutingDocs.ContentFinders -{ - public class My404ContentFinder : IContentLastChanceFinder - { - private readonly IDomainService _domainService; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - - public My404ContentFinder(IDomainService domainService, IUmbracoContextAccessor umbracoContextAccessor) - { - _domainService = domainService; - _umbracoContextAccessor = umbracoContextAccessor; - } - - public Task TryFindContent(IPublishedRequestBuilder contentRequest) - { - // Find the root node with a matching domain to the incoming request - var allDomains = _domainService.GetAll(true).ToList(); - var domain = allDomains? - .FirstOrDefault(f => f.DomainName == contentRequest.Uri.Authority - || f.DomainName == $"https://{contentRequest.Uri.Authority}" - || f.DomainName == $"http://{contentRequest.Uri.Authority}"); - - var siteId = domain != null ? domain.RootContentId : allDomains.Any() ? allDomains.FirstOrDefault()?.RootContentId : null; - - if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) - { - return Task.FromResult(false); - } - - if (umbracoContext.Content == null) - return new Task(() => contentRequest.PublishedContent is not null); - - var siteRoot = umbracoContext.Content.GetById(false, siteId ?? -1); - - if (siteRoot is null) - { - return Task.FromResult(false); - } - - // Assuming the 404 page is in the root of the language site with alias fourOhFourPageAlias - var notFoundNode = siteRoot.Children?.FirstOrDefault(f => f.ContentType.Alias == "fourOhFourPageAlias"); - - if (notFoundNode is not null) - { - contentRequest.SetPublishedContent(notFoundNode); - } - - // Return true or false depending on whether our custom 404 page was found - return Task.FromResult(contentRequest.PublishedContent is not null); - } - } -} -``` - -You can configure Umbraco to use your own implementation in the `ConfigureServices` method of the `Startup` class in `Startup.cs`: - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - // If you need to add something Umbraco specific, do it in the "AddUmbraco" builder chain, using the IUmbracoBuilder extension methods. - .SetContentLastChanceFinder() - .Build(); -} -``` diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/backoffice-see-prod.png b/10/umbraco-cms/reference/routing/request-pipeline/images/backoffice-see-prod.png deleted file mode 100644 index ee802086d4d..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/backoffice-see-prod.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/culture-and-hostnames-v8.png b/10/umbraco-cms/reference/routing/request-pipeline/images/culture-and-hostnames-v8.png deleted file mode 100644 index e5b3da02cad..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/culture-and-hostnames-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/culture-and-hostnames.png b/10/umbraco-cms/reference/routing/request-pipeline/images/culture-and-hostnames.png deleted file mode 100644 index 5c2570a56a6..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/culture-and-hostnames.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/no-sitedomainhelp.png b/10/umbraco-cms/reference/routing/request-pipeline/images/no-sitedomainhelp.png deleted file mode 100644 index f5eb3192b10..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/no-sitedomainhelp.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/path-example-v8.png b/10/umbraco-cms/reference/routing/request-pipeline/images/path-example-v8.png deleted file mode 100644 index ba2377d00d6..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/path-example-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/path-example.png b/10/umbraco-cms/reference/routing/request-pipeline/images/path-example.png deleted file mode 100644 index 34f87c24f25..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/path-example.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/simple-content-tree-v8.png b/10/umbraco-cms/reference/routing/request-pipeline/images/simple-content-tree-v8.png deleted file mode 100644 index bd3e00d55ee..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/simple-content-tree-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/simple-content-tree.png b/10/umbraco-cms/reference/routing/request-pipeline/images/simple-content-tree.png deleted file mode 100644 index 2ee40ebeb99..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/simple-content-tree.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/staging-only-staging.png b/10/umbraco-cms/reference/routing/request-pipeline/images/staging-only-staging.png deleted file mode 100644 index d2fd4280321..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/staging-only-staging.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/what-is-the-pipeline.png b/10/umbraco-cms/reference/routing/request-pipeline/images/what-is-the-pipeline.png deleted file mode 100644 index d6f646b606f..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/what-is-the-pipeline.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/images/zpqrtbnk-status-345125834434158592.png b/10/umbraco-cms/reference/routing/request-pipeline/images/zpqrtbnk-status-345125834434158592.png deleted file mode 100644 index 2e54304afd1..00000000000 Binary files a/10/umbraco-cms/reference/routing/request-pipeline/images/zpqrtbnk-status-345125834434158592.png and /dev/null differ diff --git a/10/umbraco-cms/reference/routing/request-pipeline/inbound-pipeline.md b/10/umbraco-cms/reference/routing/request-pipeline/inbound-pipeline.md deleted file mode 100644 index 27aea8e1a7b..00000000000 --- a/10/umbraco-cms/reference/routing/request-pipeline/inbound-pipeline.md +++ /dev/null @@ -1,67 +0,0 @@ ---- - - -meta.Title: "Inbound request pipeline" -description: "How the Umbraco inbound request pipeline works" ---- - -# Inbound request pipeline - -The inbound process is triggered by `UmbracoRouteValueTransformer` and then handled with the Published router. The **[published content request preparation](published-content-request-preparation.md)** process kicks in and creates a `PublishedRequestBuilder` which will be used to create a `PublishedContentRequest`. - -The `PublishedContentRequest` object represents the request which Umbraco must handle. It contains everything that will be needed to render it. All this occurs when the Umbraco modules knows that an incoming request maps to a document that can be rendered. - -```csharp -public class PublishedContentRequest -{ - public Uri Uri { get; } - … -} -``` - -There are 3 important properties, which contains all the information to find a node: - -```csharp -public bool HasDomain { get; } -public DomainAndUri Domain { get; } -public CultureInfo Culture { get; } -``` -Domain is a DomainAndUri object that is a standard Domain plus the fully qualified uri. For example, the Domain may contain "example.com" whereas the Uri will be fully qualified for example "https://example.com/". - -It contains the content to render: - -```csharp -public bool HasPublishedContent { get; } -public IPublishedContent PublishedContent { get; set; } -public bool IsInternalRedirect { get; } -public bool IsRedirect {get; } -``` - -Contains template information: - -```csharp -public bool HasTemplate { get; } -public string GetTemplateAlias { get; } -public ITemplate Template {get; } -``` - -The published request is created using the `PublishedRequestBuilder`, which implements `IPublishedRequestBuilder`. It's only in this builder that it's possible to set values, such as domain, culture, published content, redirects, and so on. - -You can subscribe to the 'routing request' notification, which is published right after the `PublishedRequestBuilder` has been prepared, but before the request is built, and processed. Here you can modify anything in the request before it is built and processed! For example content, template, etc: - -```C# -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco9.NotificationHandlers -{ - public class PublishedRequestHandler : INotificationHandler - { - public void Handle(RoutingRequestNotification notification) - { - var requestBuilder = notification.RequestBuilder; - // Do something with the IPublishedRequestBuilder here - } - } -} -``` \ No newline at end of file diff --git a/10/umbraco-cms/reference/routing/request-pipeline/outbound-pipeline.md b/10/umbraco-cms/reference/routing/request-pipeline/outbound-pipeline.md deleted file mode 100644 index 4295940d4a1..00000000000 --- a/10/umbraco-cms/reference/routing/request-pipeline/outbound-pipeline.md +++ /dev/null @@ -1,481 +0,0 @@ ---- -meta.Title: Outbound request pipeline ---- - -# Outbound request pipeline - -The **outbound pipeline** consists out of the following steps: - -1. [Create segments](#1-create-segments) -2. [Create paths](#2-create-paths) -3. [Create urls](#3-creating-urls) - -To explain things we will use the following content tree: - -![content tree](images/simple-content-tree-v8.png) - -## 1. Create segments - -When the URL is constructed, Umbraco will convert every node in the tree into a segment. Each published [Content](../../management/models/content.md) item has a corresponding url segment. - -In our example "Our Products" will become "our-products" and "Swibble" will become "swibble". - -The segments are created by the "Url Segment provider" - -### Url Segment Provider - -The DI container of an Umbraco implementation contains a collection of `UrlSegmentProviders`. This collection is populated during Umbraco boot up. Umbraco ships with a 'DefaultUrlSegmentProvider' - but custom implementations can be added to the collection. - -When the `GetUrlSegment` extension method is called for a content item + culture combination, each registered `IUrlSegmentProvider` in the collection is executed in 'collection order'. This continues until a particular `UrlSegmentProvider` returns a segment value for the content, and no further `UrlSegmentProviders` in the collection will be executed. If no segment is returned by any provider in the collection a `DefaultUrlSegmentProvider` will be used to create a segment. This ensures that a segment is always created, like when a default provider is removed from a collection without a new one being added. - -To create a new Url Segment Provider, implement the following interface: - -```csharp -public interface IUrlSegmentProvider -{ - string GetUrlSegment(IContentBase content, string? culture = null); -} -``` - -Note each 'culture' variation can have a different Url Segment! - -The returned string will be the Url Segment for this node. Any string value can be returned here but it cannot contain the URL segment separator character `/`. This would create additional "segments" - something like `5678/swibble` is not allowed. - -#### Example - -For the segment of a 'product page', add its unique SKU / product ref to the existing Url segment: - -```csharp -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Strings; - -namespace RoutingDocs.SegmentProviders -{ - public class ProductPageUrlSegmentProvider : IUrlSegmentProvider - { - private readonly IUrlSegmentProvider _provider; - - public ProductPageUrlSegmentProvider(IShortStringHelper stringHelper) - { - _provider = new DefaultUrlSegmentProvider(stringHelper); - } - - public string GetUrlSegment(IContentBase content, string? culture = null) - { - // Only apply this rule for product pages - if (content.ContentType.Alias != "productPage") - { - return null; - } - - var segment = _provider.GetUrlSegment(content, culture); - var productSku = content.GetValue("productSKU"); - return $"{segment}--{productSku}".ToLower(); - } - } -} -``` - -The returned string becomes the native Url segment - there is no need for any Url rewriting. - -For our "swibble" product in our example content tree, the `ProductPageUrlSegmentProvider` would return a segment "swibble--123xyz". In this case, 123xyz is the unique product sku/reference for the swibble product. - -Register the custom UrlSegmentProvider with Umbraco, either using a composer or an extension method on the `IUmbracoBuilder`: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace RoutingDocs.SegmentProviders -{ - public class RegisterCustomSegmentProviderComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.UrlSegmentProviders().Insert(); - } - } -} -``` - -### The Default Url Segment Provider - -The Default Url Segment provider builds its segments by looking for one of the below values, checked in this order: - -1. A property with alias _umbracoUrlName_ on the node. (this is a convention led way of giving editors control of the segment name - with variants - this can vary by culture). -2. The 'name' of the content item e.g. `content.Name`. - -The Umbraco string extension `ToUrlSegment()` is used to produce a clean 'Url safe' segment. - -## 2. Create paths - -To create a path, the pipeline will use the segments of each node to produce a path. - -If we look at our example, the "swibble" node will receive the path: "/our-products/swibble". If we take the `ProductPageUrlSegmentProvider` from above, the path would become: "/our-products/swibble-123xyz". - -### Multiple sites in a single Umbraco implementation - -But, what if there are multiple websites in a single Umbraco Implementation? in this multi-site scenario then an (internal) path to a node such as "/our-products/swibble-123xyz" could belong to any of the sites, or match multiple nodes in multiple sites. In this scenario additional sites will have their internal path prefixed by the node id of their root node. Any content node with a hostname defines a “new root” for paths. - -![path example](images/path-example-v8.png) - -| Node | Segment | Internal Path | -| ------------ | -------------- | ---------------------------- | -| Our Values | our-values | /our-values | -| Our Products | our-products | /our-products | -| Swibble | swibble-123xyz | /our-products/swibble-123xyz | -| Dibble | dibble-456abc | /our-products/dibble-456abc | -| Another Site | another-site | **9676**/ | -| Their Values | their-values | **9676**/their-values | - -Paths can be cached, what comes next cannot (http vs https, current request…). - -#### Some further considerations when **working with hostnames** - -* **Domain without path** e.g. "www.site.com" will become "1234/path/to/page" -* **Domain with path** e.g. "www.site.com/dk" will produce "1234/dk/path/to/page" as path -* **No domain specified**: "/path/to/page" -* **Unless HideTopLevelNodeFromPath config is true**, then the path becomes "/to/page" - -## 3. Creating Urls - -The Url of a node consists of a complete [URI](https://en.wikipedia.org/wiki/Uniform\_Resource\_Identifier): the Schema, Domain name, (port) and the path. - -In our example the "swibble" node could have the following URL: "http://example.com/our-products/swibble" - -Generating this url is handled by the Url Provider. The Url Provider is called whenever a request is made in code for a Url e.g.: - -```csharp -@Model.Url -@Umbraco.Url(1234) -@UmbracoContext.UrlProvider.GetUrl(1234); -``` - -The DI container of an Umbraco implementation contains a collection of `UrlProviders` this collection is populated during Umbraco boot up. Umbraco ships with a `DefaultUrlProvider` - but custom implementations can be added to the collection. When .Url is called each `IUrlProvider` registered in the collection is executed in 'collection order' until a particular `IUrlProvider` returns a value. (and no further `IUrlProviders` in the collection will be executed.) - -### DefaultUrlProvider - -Umbraco ships with a `DefaultUrlProvider`, which provides the implementation for the out of the box mapping of the structure of the content tree to the url. - -```csharp -// This one is initialized by default -public class DefaultUrlProvider : IUrlProvider -{ - public virtual UrlInfo GetUrl(IPublishedContent content, UrlMode mode, string? culture, Uri current) - {…} - - public virtual IEnumerable GetOtherUrls(int id, Uri current) - {…} -} -``` - -### How the Default Url provider works - -* If the current domain matches a root domain of the target content. - * Return a relative Url. - * Else must return an absolute Url. -* If the target content has only one root domain. - * Use that domain to build the absolute Url. -* If the target content has more than one root domain. - * Figure out which one to use. - * To build the absolute Url. -* Complete the absolute Url with scheme (http vs https). - * If the domain contains a scheme use it. - * Else use the current request’s scheme. -* If "addTrailingSlash" is true, then add a slash. -* Then add the virtual directory. - -If the URL provider encounters collisions when generating content URLs, it will always select the first available node and assign the URL to this one. The remaining nodes will be marked as colliding and will not have a URL generated. Fetching the URL of a node with a collision URL will result in an error string including the node ID (#err-1094) since this node does not currently have an active URL. This can happen if an umbracoUrlName property is being used to override the generated URL of a node, or in some cases when having multiple root nodes without hostnames assigned. - -{% hint style="warning" %} -This means publishing an unpublished node with a conflicting URL, might change the active node being rendered on that specific URL in cases where the published node should now take priority according to sort order in the tree! -{% endhint %} - -### Custom Url Provider - -Create a custom Url Provider by implementing `IUrlProvider` interface: - -```csharp -public interface IUrlProvider -{ - UrlInfo? GetUrl(IPublishedContent content, UrlMode mode, string? culture, Uri current); - - IEnumerable GetOtherUrls(int id, Uri current); -} -``` - -The url returned in the 'UrlInfo' object by GetUrl can be completely custom. - -If implementing a custom Url Provider, consider following things: - -* Cache things. -* Be sure to know how to handle schema's (http vs https) and hostnames. -* Inbound might require rewriting. - -{% hint style="info" %} -If there is only a small change to the logic around Url generation, then a smart way to create a custom Url Provider is to inherit from the DefaultUrlProvider and override the GetUrl() virtual method. -{% endhint %} - -#### Example - -Add /fish on the end of every url. It's important to note here that since we're changing the outbound url, but not how we handle urls inbound, this **will** break the routing. In order to make the routing work again you have to implement a custom content finder, see [IContentFinder](icontentfinder.md) for more information on how to do that. - -```csharp -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Web; - -namespace RoutingDocs.UrlProviders -{ -public class ProductPageUrlProvider : DefaultUrlProvider - { - public ProductPageUrlProvider( - IOptionsMonitor requestSettings, - ILogger logger, - ISiteDomainMapper siteDomainMapper, - IUmbracoContextAccessor umbracoContextAccessor, - UriUtility uriUtility, - ILocalizationService localizationService) - : base(requestSettings, logger, siteDomainMapper, umbracoContextAccessor, uriUtility, localizationService) - { - } - - public override IEnumerable GetOtherUrls(int id, Uri current) - { - // Add custom logic to return 'additional urls' - this method populates a list of additional urls for the node to display in the Umbraco backoffice - return base.GetOtherUrls(id, current); - } - - public override UrlInfo? GetUrl(IPublishedContent content, UrlMode mode, string? culture, Uri current) - { - if (content is null) - { - return null; - } - - // Only apply this to product pages - if (content.ContentType.Alias == "productPage") - { - // Get the original base url that the DefaultUrlProvider would have returned, - // it's important to call this via the base, rather than .Url, or UrlProvider.GetUrl to avoid cyclically calling this same provider in an infinite loop!!) - UrlInfo? defaultUrlInfo = base.GetUrl(content, mode, culture, current); - if (defaultUrlInfo is null) - { - return null; - } - - if (!defaultUrlInfo.IsUrl) - { - // This is a message (eg published but not visible because the parent is unpublished or similar) - return defaultUrlInfo; - } - else - { - // Manipulate the url somehow in a custom fashion: - var originalUrl = defaultUrlInfo.Text; - var customUrl = $"{originalUrl}fish/"; - return new UrlInfo(customUrl, true, defaultUrlInfo.Culture); - } - } - // Otherwise return the base GetUrl result: - return base.GetUrl(content, mode, culture, current); - } - } -} -``` - -Register the custom UrlProvider with Umbraco: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace RoutingDocs.UrlProviders -{ - public class RegisterCustomUrlProviderComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.UrlProviders().Insert(); - } - } -} -``` - -### GetOtherUrls - -The GetOtherUrls method is only used in the Umbraco Backoffice to provide a list to editors of other Urls which also map to the node. - -For example, let's consider a convention-led `umbracoUrlAlias` property that enables editors to specify a comma delimited list of alternative urls for the node. It has a corresponding `AliasUrlProvider` registered in the `UrlProviderCollection` to display this list to the Editor in the backoffice Info Content app for a node. - -### Url Provider Mode - -Specifies the type of urls that the url provider should produce, eg. absolute vs. relative Urls. Auto is the default - -These are the different modes: - -```csharp -public enum UrlMode -{ - /// - /// Indicates that the url provider should do what it has been configured to do. - /// - Default = 0, - - /// - /// Indicates that the url provider should produce relative urls exclusively. - /// - Relative, - - /// - /// Indicates that the url provider should produce absolute urls exclusively. - /// - Absolute, - - /// - /// Indicates that the url provider should determine automatically whether to return relative or absolute urls. - /// - Auto -} -``` - -Default setting can be changed in the Umbraco:CMS:WebRouting section of `appsettings.json`: - -```json -"Umbraco": { - "CMS": { - "WebRouting": { - "UrlProviderMode": "Relative" - } - } -} -``` - -See [WebRouting config reference documentation](../../configuration/webroutingsettings.md) for more information on routing settings. - -### Site Domain Mapper - -The `ISiteDomainMapper` implementation is used in the `IUrlProvider` and filters a list of `DomainAndUri` to pick one that best matches the current request. - -Create a custom SiteDomainMapper by implementing ISiteDomainMapper - -```csharp -public interface ISiteDomainMapper -{ - DomainAndUri? MapDomain(IReadOnlyCollection domainAndUris, Uri current, string? culture, string? defaultCulture); - IEnumerable MapDomains(IReadOnlyCollection domainAndUris, Uri current, bool excludeDefault, string? culture, string? defaultCulture); -} -``` - -The MapDomain methods will receive the Current Uri of the request, and custom logic can be implemented to decide upon the preferred domain to use for a site in the context of that request. The SiteDomainMapper's role is to get the current Uri and all eligible domains, and only return one domain which is then used by the UrlProvider to create the Url. - -Only a single `ISiteDomainMapper` can be registered with Umbraco. - -Register the custom `ISiteDomainMapper` with Umbraco using the `SetSiteDomainHelper` extension method - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Extensions; - -namespace RoutingDocs.SiteDomainMapper -{ - public class RegisterCustomSiteDomainMapperComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.SetSiteDomainHelper(); - } - } -} -``` - -### Default SiteDomainMapper - -Umbraco ships with a default `SiteDomainMapper`. This has some useful functionality for grouping sets of domains together. With Umbraco Cloud, or another Umbraco development environment scenario, there maybe be multiple domains setup for a site 'live, 'staging', 'testing' or a separate domain to access the backoffice. Each domain will be setup as a 'Culture and Hostname' inside Umbraco. By default editors will see the full list of possible Urls for each of their content items on each domain, which can be confusing. If the additional urls aren't present in Culture and Hostnames, then when testing the front-end of the site on a 'staging' url, will result in navigation links taking you to the registered domain! - -![Culture and Hostnames multiple domains](images/culture-and-hostnames-v8.png) - -What the editor sees without any SiteDomainMapper, visiting the backoffice url: - -![All domains listed](images/no-sitedomainhelp.png) - -Which is 'noise' and can lead to confusion: accidentally clicking the staging url, which is likely to be served from a different environment / different database etc may display the wrong content... - -To avoid this problem, use the default SiteDomainMapper's AddSite method to group Urls together. - -Since the SiteDomainMapper is registered in the DI, we can't consume it directly from a composer, so first create a component which adds the sites in the initialize method: - -```csharp -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Routing; - -namespace RoutingDocs.SiteDomainMapping -{ - public class SiteDomainMapperComponent : IComponent - { - private readonly SiteDomainMapper? _siteDomainMapper; - - public SiteDomainMapperComponent(ISiteDomainMapper siteDomainMapper) - { - // SiteDomainMapper can be overwritten, so ensure it's the default one which contains the AddSite - if (siteDomainMapper is SiteDomainMapper concreteSiteDomainMapper) - { - _siteDomainMapper = concreteSiteDomainMapper; - } - } - public void Initialize() - { - _siteDomainMapper?.AddSite("backoffice", "umbraco-v8-backoffice.localtest.me", "umbraco-v8.localtest.me"); - _siteDomainMapper?.AddSite("preproduction", "umbraco-v8-preprod.localtest.me"); - _siteDomainMapper?.AddSite("staging", "umbraco-v8-staging.localtest.me"); - } - - public void Terminate() - { } - } -} -``` - -Then add the component with a composer: - -``` -using Umbraco.Cms.Core.Composing; - -namespace RoutingDocs.SiteDomainMapping -{ - public class AddSiteComposer : ComponentComposer - { } -} -``` - -Now if an editor visits the backoffice via the staging url they will only see domains for the staging url: - -![Staging domain only](images/staging-only-staging.png) - -Now if an editor visits the backoffice via the backoffice url they will only see domains for the backoffice url and the production url: - -![Backoffice + production domains only](images/backoffice-see-prod.png) - -NB: it's not a 1-1 mapping, but a grouping. Multiple Urls can be added to a group. Think multilingual production and staging variations, and in the example above, if an editor logged in to the backoffice via the production url, eg umbraco-v8.localtest.me/umbraco - they would see the umbraco-v8-backoffice.localtest.me domain listed. - -#### Grouping the groupings - BindSites - -The SiteDomainMapper contains a 'BindSites' method that enables different site groupings to be bound together: - -```csharp -public void Initialize() -{ - _siteDomainMapper?.AddSite("backoffice", "umbraco-v8-backoffice.localtest.me", "umbraco-v8.localtest.me"); - _siteDomainMapper?.AddSite("preproduction", "umbraco-v8-preprod.localtest.me"); - _siteDomainMapper?.AddSite("staging", "umbraco-v8-staging.localtest.me"); - _siteDomainMapper?.BindSites("backoffice", "staging"); -} -``` - -Visiting the backoffice now via umbraco-v8-backoffice.localtest.me/umbraco would list all the 'backoffice' grouped domains AND all the 'staging' grouped domains. diff --git a/10/umbraco-cms/reference/routing/request-pipeline/published-content-request-preparation.md b/10/umbraco-cms/reference/routing/request-pipeline/published-content-request-preparation.md deleted file mode 100644 index 0c3b2991fa6..00000000000 --- a/10/umbraco-cms/reference/routing/request-pipeline/published-content-request-preparation.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -meta.Title: Published Content Request Preparation -description: How Umbraco prepares content requests ---- - -# Published Content Request Preparation - -Is started in `UmbracoRouteValueTransformer` where it gets the `HttpContext` and `RouteValueDictionary` from the netcore framework: - -```c# - async ValueTask TransformAsync(…) -``` - -What it does: - -* It ensures Umbraco is ready, and the request is a document request. -* Ensures there's content in the published cache, if there isn't it routes to the `RenderNoContentController` which displays the no content page you see when running a fresh install. -* Creates a published request builder. -* Routes the request with the request builder using the `PublishedRouter.RouteRequestAsync(…)`. - * This will handle redirects, find domain, template, published content and so on. - * Build the final `IPublishedRequest`. -* Sets the routed request in the Umbraco context, so it will be available to the controller. -* Create the route values with the `UmbracoRouteValuesFactory`. - * This is what actually routes your request to the correct controller and action, and allows you to hijack routes. -* Set the route values to the http context. -* Handles posted form data. -* Returns the route values to netcore so it routes your request correctly. - -## RouteRequestAsync - -When the `RouteRequestAsync` method is invoked on the `PublishedRouter` it will: - -* FindDomain(). -* Handle redirects. -* Set culture. -* Find the published content. - * Only if it doesn't exist, allowing you to handle it in a custom way with a custom router handler. -* Find the template. -* Set the culture (again, in case it was changed). -* Publish `RoutingRequestNotification`. -* Handle redirects and missing content. -* Initialize a few internal stuff. - -We will discuss a few of these steps below. - -### FindDomain() - -The FindDomain method looks for a domain matching the request Uri - -* Using a greedy match: “domain.com/foo” takes over “domain.com”. -* Sets published content request’s domain. -* If a domain was found. - * Sets published content request’s culture accordingly. - * Computes domain Uri based upon the current request ("domain.com" for "http://domain.com" or "https://domain.com"). -* Else. - * Sets published content request’s culture by default (first language, else system). - -### Find published content - -When finding published content the `PublishedRouter` will first check if the `PublishedRequestBuilder` already has content, if it doesn't the content finders will kick in. There a many different types of content finders, such as find by url, by id path, and more. If none of the content finders manages to find any content, the request will be set as 404, and the `ContentLastChanceFinder` will run, this will try to find a page to handle a 404, if it can't find one, the ugly 404 will be used. - -You can also implement your own content finders and last chance finder, for more information, see [IContentFinder](icontentfinder.md) - -The `PublishedRouter` will also follow any internal redirects, but it is limited to avoid spiraling out of control due to an infinite redirect loop. - -### Find template - -Once the content has been found, the `PublishedRouter` moves on to finding the template. - -First off it checks if any content was found, if it wasn't it sets the template to null, since there can't be a template without content. - -Next it checks to see if there is an alternative template which should be used. An alternative template will be used if the router can find a value with the key "altTemplate", in either the querystring, form, or cookie, and there is content found by the contentfinders, so not the 404 page, or it's an internal redirect and the web routing setting has `InternalRedirectPreservesTemplate`. - -If no alternative template is found the router will get the template with the file service, using the ID specified on the published content, and then assign the template to the request. - -If an alternative template is specified, the router will check if it's an allowed template for the content, if the template is not allowed on that specific piece of content it will revert to using the default template. If the template is allowed it will then use the file service to get the specified alternative template and assign the template to the request. - -### Redirects - -The router will pick up the redirect and redirect. There is no need to write your own redirects: - -```csharp -PublishedContentRequest.Prepared += (sender, args) => -{ -public void Handle(RoutingRequestNotification notification) -{ - var requestBuilder = notification.RequestBuilder; - var content = requestBuilder.PublishedContent; - var redirect = content.Value("myRedirect"); - if (!string.IsNullOrWhiteSpace(redirect)) - { - requestBuilder.SetRedirect(redirect); - } -} -} -``` - -## Missing template? - -In case the router can't find a template, it will try and verify if there's route hijacking in place, if there is, it will run the hijacked route. If route hijacking is not in place, the router will set the content to null, and run through the routing of the request again, in order for the last chance finder to find a 404. diff --git a/10/umbraco-cms/reference/routing/routing-properties.md b/10/umbraco-cms/reference/routing/routing-properties.md deleted file mode 100644 index 27dd9cca421..00000000000 --- a/10/umbraco-cms/reference/routing/routing-properties.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -meta.Title: Special Property Type Aliases for Routing -description: Describes special property type aliases which can be used to customise routing ---- - -# Special Property Type aliases for routing - -_There are a few special/reserved Umbraco Property Type aliases that can be used which can manipulate how the standard Umbraco routing pipeline works. You can add these Property Types to any Document Type and if values are assigned to these properties, Umbraco will adjust its routing accordingly. See below for full details._ - -## umbracoRedirect - -Creating a property alias with this name and using a Content Picker property editor lets you create a 302 temporary redirect. This in effect means that when a user navigates to this node, they will be redirected away from it. - -## umbracoInternalRedirectId - -Add this property alias to your Document Type with a Content Picker property editor and Umbraco will load the selected page’s content transparently without performing any URL redirection. This essentially performs a rewrite. - -## umbracoUrlName - -This property when created as a text string lets you provide a different URL name to what is created by default by the name of the node. If you enter a value for this property and save/publish the content node you will see that its main URL is updated with a new path suffix. - -## umbracoUrlAlias - -This property when created as a text string lets you provide a comma separated list of alternate full URL paths for the node. For example, if your URL was /some-category/some-page/content-node, by adding an umbracoUrlAlias of "flowers", a user can navigate to the node by going to /flowers. The URL alias remains in the browser address bar as a 'mask' over the real URL. You can also specify paths like "flowers/roses/red". - -## Filtering - -[See Filtering Property Conventions](../querying/ipublishedcontent/collections.md#filtering-conventions) diff --git a/10/umbraco-cms/reference/routing/surface-controllers/README.md b/10/umbraco-cms/reference/routing/surface-controllers/README.md deleted file mode 100644 index 2d0b611dcd0..00000000000 --- a/10/umbraco-cms/reference/routing/surface-controllers/README.md +++ /dev/null @@ -1,237 +0,0 @@ ---- - - -meta.Title: "Surface Controllers" -description: "Information about Surface Controllers in Umbraco" ---- - -# Surface controllers - -_A surface controller is an MVC controller that interacts with the front-end rendering of an Umbraco page. They can be used for rendering view components and for handling form data submissions. Surface controllers are auto-routed, meaning that you don't have to add/create your own routes for these controllers to work._ - -## What is a surface controller? - -It is a regular ASP.NET Core MVC controller that: - -* Is auto-routed, meaning you don't have to setup any custom routes to make it work -* Is used for interacting with the front-end of Umbraco (not the backoffice) - -Since any surface controller inherits from the `Umbraco.Cms.Web.Website.Controllers.SurfaceController` class, the controller instantly supports many of the helper methods and properties that are available on the base `SurfaceController` class including `UmbracoContext`. Therefore, all surface controllers have native Umbraco support for: - -* Interacting with Umbraco routes during HTTP POSTs (i.e. `return CurrentUmbracoPage();` ) -* Rendering forms in Umbraco (i.e. `@using (Html.BeginUmbracoForm(...)){}` ) -* Rendering of ASP.NET Core MVC view components - -## Creating a surface controller - -Surface controllers are plugins, meaning they are found when the Umbraco application boots. There are 2 types of surface controllers: **locally declared** & **plugin based**. The main difference between the two is that a plugin based controller gets routed via an MVC area, which is defined in the controller (see below). Because a plugin based controller is routed via an MVC area, it means that the views can be stored in a custom folder specific to the package it is being shipped in. This can be done without interfering with the local developer's MVC view files. - -### Locally declared controllers - -A locally declared surface controller is one that is not shipped within an Umbraco package. It is created by the developer of the website they are creating. If you are planning on shipping a surface controller in an Umbraco package, then you will need to create a plugin based surface controller (see the next heading). - -To create a locally declared surface controller: - -* Create a controller that inherits from `Umbraco.Cms.Web.Website.Controllers.SurfaceController` -* The controller must be a public class. -* The controller must call the base constructor of `SurfaceController` -* The controller's name must be suffixed with the term `Controller` -* The controller must be inside a namespace - -For example: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Website.Controllers; - -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - public IActionResult Index() - { - return Content("Hello world"); - } - } -} -``` - -#### Routing for locally declared controllers - -All locally declared controllers gets routed to: - - /umbraco/surface/{controllername}/{action}/{id} - -They do not get routed via an MVC area, so any views must exist in the following folders: - -* `/Views/{controllername}/` -* `/Views/Shared/` -* `/Views/` - -{% hint style="info" %} -If you get a 404 error when trying to access your surface controller, you may have forgotten to add a namespace to it! -{% endhint %} - -## Plugin based controllers - -If you are shipping a surface controller in a package, then you should definitely be creating a plugin based surface controller. The only difference between creating a plugin based controller and locally declared controller, is that you need to add an attribute to your class, which defines the MVC area you'd like your controller to be routed through. Here's an example: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.Attributes; -using Umbraco.Cms.Web.Website.Controllers; - -namespace SurfaceControllerPackage -{ - [PluginController("SurfaceControllerPackage")] - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - public IActionResult Index() - { - return Content("Hello world"); - } - } -} -``` - -In the above, the surface controller will belong to the MVC area called 'SurfaceControllerPackage'. Perhaps it is obvious, but if you are creating a package that contains many surface controllers, then you should most definitely ensure that all of your controllers are routed through the same MVC area. - -### Routing for plugin based controllers - -All plugin based controllers get routed to: - - /umbraco/{areaname}/{controllername}/{action}/{id} - -Since they get routed via an MVC area, your views should be placed in the following folder: - -* `~/App_Plugins/{areaname}/Views/{controllername}/` -* `~/App_Plugins/{areaname}/Views/Shared/` - -Since you can only place static files in your package's `App_Plugin` folder, it is highly recommended to use a name that matches your package. This helps ensure your views can be found. - -The controller itself should not be placed in the App_Plugins folder, the App_Plugins folder is for static files only, compiled files like the controller will be included in the dlls used by the nuget package. - -#### Protecting surface controller routes - -If you only want a surface controller action to be available when it's used within an Umbraco form and not from the auto-routed URL, you can add the `[ValidateUmbracoFormRouteString]` attribute to the action method. This can be especially useful for plugin based controllers, as this makes sure the actions can only be activated from a form whenever it's used within the website. - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - [ValidateUmbracoFormRouteString] - public IActionResult HandleSubmit() - { - return RedirectToCurrentUmbracoPage(); - } - } -} -``` - -Whenever you render an Umbraco form within your view using `Html.BeginUmbracoForm(...)`, the forms action will be the URL of the current page (not the auto-routed URL of the surface controller). Umbraco will therefore add a hidden `ufprt` field to the form with an encrypted value containing the controller, action and optional area (known as the 'Umbraco form route string'). On form submission, this value is decrypted and Umbraco will activate the specified action of the surface controller. - -```html -@using (Html.BeginUmbracoForm("HandleSubmit")) -{ - -} -``` - -{% hint style="info" %} -In Umbraco 9 the `__RequestVerificationToken` token is automatically added to forms for you, so you no longer need to add `@Html.AntiForgeryToken()` to your forms. -{% endhint %} - -### Preventing Cross-Site Request Forgery (XSRF/CSRF) Attacks - -Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated. - -{% hint style="info" %} -By default, `Html.BeginUmbracoForm` and `Html.BeginForm` adds an antiforgery token. -{% endhint %} - -If the token is not added automatically, for instance, if you don't use `Html.BeginUmbracoForm` or use an overload to `Html.BeginForm` where you've set the `antiForgery` parameter to false, you can add it manually like so: - -```cs -@using (Html.BeginForm(nameof(ContactFormController.Submit), "ContactForm", new object(), FormMethod.Post, false /* this is where you disable it */, new object())) -{ - @Html.AntiForgeryToken() - // Add your form fields here -} -``` - -If you are using a SurfaceController the antiforgery token will automatically be validated. However, if you are using a standard (non-umbraco) controller, you can manually specify it with the `ValidateAntiForgeryToken` attribute: - -```cs -[HttpPost] -[ValidateAntiForgeryToken] -public ActionResult EditAction(FormViewModel formData) -{ - // Handle your form submit here -} -``` - -The `BeginUmbracoForm` and `BeginForm` will only add the antiforgery token to the form as a hidden input. This means that you have to manually handle this if you're sending the request via JavaScript, for example, ajax. - -The routing expects the antiforgery token to be in a header called `RequestVerificationToken`. You can use the `beforeSend` hook to read the antiforgery token and set it as a header if you're using ajax: - -```js -$.ajax({ - beforeSend: function (xhr) { - xhr.setRequestHeader("RequestVerificationToken", - $('input:hidden[name="__RequestVerificationToken"]').val()); - } -}); -``` - -For more information, see the [Antiforgery in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-6.0#antiforgery-in-aspnet-core-1) article. - -### Surface Controller Actions - -You can read more about the surface controller [action result helpers](surface-controllers-actions.md). diff --git a/10/umbraco-cms/reference/routing/surface-controllers/surface-controllers-actions.md b/10/umbraco-cms/reference/routing/surface-controllers/surface-controllers-actions.md deleted file mode 100644 index 9e419203d0b..00000000000 --- a/10/umbraco-cms/reference/routing/surface-controllers/surface-controllers-actions.md +++ /dev/null @@ -1,199 +0,0 @@ ---- - - -meta.Title: "Surface Controller Actions" -description: "Information about Surface Controller Actions Result Helpers in Umbraco" ---- - -# Surface controller actions - -A surface controller can return a few Umbraco specific actions. - -## CurrentUmbracoPage - -Returns the current Umbraco page. - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult PostMethod() - { - if (!ModelState.IsValid) - { - return CurrentUmbracoPage(); - } - - return RedirectToCurrentUmbracoPage(); - } - } -} -``` - -## RedirectToCurrentUmbracoPage - -Redirects to the currently rendered Umbraco page. - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult PostMethod() - { - if (!ModelState.IsValid) - { - return CurrentUmbracoPage(); - } - - return RedirectToCurrentUmbracoPage(); - } - } -} -``` - -This action can also take in a `QueryString` object to be included in the redirect. - -### Querystring parameter using a string value - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult PostMethod() - { - var paramValue = "someValue"; - var queryString = QueryString.Create("param", paramValue); - return RedirectToCurrentUmbracoPage(queryString); - } - } -} -``` - -## RedirectToCurrentUmbracoUrl - -Redirects to the currently rendered Umbraco url. - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult PostMethod() - { - return RedirectToCurrentUmbracoUrl(); - } - } -} -``` - -## RedirectToUmbracoPage - -Redirects to a given Umbraco page. - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult PostMethod() - { - // Gets the first child page of the current page - var childPage = CurrentPage.FirstChild(); - return RedirectToUmbracoPage(childPage); - } - } -} -``` - -You can also redirect to a page key (GUID). - -```csharp -namespace RoutingDocs.Controllers -{ - public class MyController : SurfaceController - { - public MyController( - IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, - IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) - { - } - - [HttpPost] - public IActionResult PostMethod() - { - var childPage = CurrentPage.FirstChild(); - return RedirectToUmbracoPage(childPage.Key); - } - } -} -``` - -There are overloads for adding a `QueryString` object. diff --git a/10/umbraco-cms/reference/routing/umbraco-api-controllers/README.md b/10/umbraco-cms/reference/routing/umbraco-api-controllers/README.md deleted file mode 100644 index 9a1f8843ffc..00000000000 --- a/10/umbraco-cms/reference/routing/umbraco-api-controllers/README.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -meta.Title: Umbraco WebApi -description: A guide to implenting WebApi in Umbraco projects ---- - -# Umbraco API Controllers - -_This section will describe how to work with Web API in Umbraco to create REST services_ - -Related links: - -* [Umbraco API routes and Urls](routing.md) -* [Umbraco API authorization](authorization.md) - -## What is Web API? - -The Microsoft Web API reference can be found on the [official ASP.NET Web API website](https://www.asp.net/web-api). - -"ASP.NET enables you to build services that reach a broad range of clients, including browsers and mobile devices. With ASP.NET you use the same framework and patterns to build both web pages and services, side-by-side in the same project." - -A great resource for getting started with creating web API's using .Net Core is the [official Microsoft documentation](https://docs.microsoft.com/en-gb/aspnet/core/web-api/?view=aspnetcore-5.0). - -## Web Api in Umbraco - -We have created a base API controller for developers to inherit from. This will ensure that the API controller gets routed. This does not expose any specific Umbraco-related services or objects but does inherit from the .Net Core controller base. This means that you will have access to the same things you would from a regular .Net Core controller. Dependency injection is also available to controllers. Any Umbraco-specific services or objects you might need can be injected into the constructor. - -The class to inherit from is: `Umbraco.Cms.Web.Common.Controllers.UmbracoApiController` - -## Creating a Web API controller - -There are 2 types of Umbraco API controllers: - -1. A locally declared controller - is **not** routed via an Area. -2. A plugin based controller - is routed via an Area. - -When working on your own projects you will normally be creating a locally declared controller which requires no additional steps. However, if you are creating an Umbraco package, to be distributed, you will want to create a plugin based controller so it gets routed via its own area. This ensures that the route will not overlap with someone's locally declared controller if they are both named the same thing. - -### Naming conventions - -It is very important that you name your controllers according to these guidelines or else they will not get routed: - -All controller class names must be suffixed with "**Controller**" and inherit from **UmbracoApiController**. Some examples: - -```csharp -public class ProductsController : UmbracoApiController -public class CustomersController : UmbracoApiController -public class ScoresController : UmbracoApiController -``` - -### Locally declared controller - -This is the most common way to create an Umbraco API controller, you inherit from the class `Umbraco.Cms.Web.Common.Controllers.UmbracoApiController` and that is all. You will need to follow the guidelines specified by Microsoft for creating a Web API controller, documentation can be found on the [official Microsoft documentation website](https://docs.microsoft.com/en-gb/aspnet/core/web-api/?view=aspnetcore-5.0). - -Example: - -```csharp -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } -} -``` - -All locally declared Umbraco API controllers will be routed under the url path of: - -`~/Umbraco/Api/[YourControllerName]` - -E.g. \*`~/Umbraco/Api/Products/GetAllProducts` - -Note that the "Controller" part of your controller name gets stripped away. - -### Plugin based controller - -If you are creating an Umbraco API controller to be shipped in an Umbraco package you will need to add the `Umbraco.Cms.Web.Common.Attributes.PluginController` attribute to your controller to ensure that it is routed via an area. The area name is up to you to specify in the attribute. - -Example: - -```csharp -[PluginController("AwesomeProducts")] -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } -} -``` - -Now this controller will be routed via the area called "AwesomeProducts". All plugin based Umbraco API controllers will be routed under the url path of: - -`~/Umbraco/[YourAreaName]/[YourControllerName]` - -E.g. `~/Umbraco/AwesomeProducts/Products/GetAllProducts` - -For more information about areas, Urls and routing see the [routing section](routing.md) - -## Backoffice controllers - -If you are creating a controller to work within the Umbraco backoffice then you will need to ensure that it is secured properly by inheriting from: `UmbracoAuthorizedApiController` or `UmbracoAuthorizedJsonController`. This controller type will auto-route your controller like the above examples except that it will add another segment to the path: 'backoffice'. - -`~/Umbraco/backoffice/Api/[YourControllerName]` - -`~/Umbraco/backoffice/[YourAreaName]/[YourControllerName]` - -E.g. `~/Umbraco/backoffice/Api/Products/GetAllProducts` or - -`~/Umbraco/backoffice/AwesomeProducts/Products/GetAllProducts` for PluginController - -### More Information - -* [Authenticating & Authorizing controllers](../authorized.md) - -## Using MVC Attribute Routing in Umbraco Web API Controllers - -_Attribute routing_ uses attributes to define routes. _Attribute routing_ gives you more control over the URIs in your web application. - -{% hint style="info" %} -To exclude any endpoint or folders in your directory from Umbraco's routing, add it to the `ReservedPaths` setting in the `appsettings.json` file. -{% endhint %} - -For example: - -```json -"Umbraco": { - "CMS": { - "Global": { - "ReservedPaths": "~/api,~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/," - } - } -} -``` - -For more information, see the [Global Settings](../../configuration/globalsettings.md) article. - -To use attribute routing, add the `Microsoft.AspNetCore.Mvc.Route` attribute to the controller or controller action you want to route. If you want to attribute route an entire controller you have to add the `[action]` token in order to route to an action, for instance: - -```C# -[Route("products/[action]")] -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } - - public string GetProduct() - { - return "Monitor"; - } -} -``` - -This route the controllers actions like so: - -`~/products/GetAllProducts` and `~/products/GetProduct` - -If you use the route attribute for a specific action the `[action]` token is not nececary, but you can request parameters from the path in a similar manner, using the `{parameterName}` syntax, for instance: - -```C# -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } - - [Route("product/{id?}")] - public string GetProduct(int? id) - { - if (id is not null) - { - return $"Monitor model {id}"; - } - return "Base model Monitor"; - } -} -``` - -Here the `GetAllProducts` endpoint will be routed normally, but the `GetProduct` will be routed as `~/product` where you can optionally access it as `~/product/4`, or any other number, if a number is included as the last segment of the path, let's say 4, the action will return "Monitor model 4", otherwise it will just return "Base model Monitor". - -This is not anything Umbraco specific, so to read more about attribute routing, see the [routing article on the official Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-5.0#attribute-routing-for-rest-apis). diff --git a/10/umbraco-cms/reference/routing/umbraco-api-controllers/authorization.md b/10/umbraco-cms/reference/routing/umbraco-api-controllers/authorization.md deleted file mode 100644 index 2cfee87f8f6..00000000000 --- a/10/umbraco-cms/reference/routing/umbraco-api-controllers/authorization.md +++ /dev/null @@ -1,106 +0,0 @@ ---- - - -meta.Title: Umbraco WebApi Authorization -description: How to secure your Umbraco Api controllers ---- - -# Umbraco Api - Authorization - -_This section will describe how to secure your Umbraco Api controllers based on a users membership_ - -## Authorizing for the backoffice - -### Inheriting from UmbracoAuthorizedApiController - -Probably the easiest way to ensure your controller is secured for only backoffice users is to inherit from `Umbraco.Cms.Web.BackOffice.Controllers.UmbracoAuthorizedApiController`. This is essentially the same as applying `[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]` to your controller (see below). - -The `UmbracoAuthorizedApiController` is automatically routed. Check out the [routing documentation](../authorized.md) for more information on this topic. - -### Using the Authorize attribute - -To secure your controller based on backoffice membership use the attribute: `Microsoft.AspNetCore.Authorization.Authorize`, with the policy parameter set to `AuthorizationPolicies.BackOfficeAccess`, like so: `[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]`. - -This attribute will ensure that a valid backoffice user is logged in, however it's very important to note that this only works if the controller is routed to `/umbraco/backoffice/*`. - -**Examples:** - -This will only allow a logged in backoffice user to access the GetAllProducts action: - -```csharp -public class ProductsController : UmbracoApiController -{ - [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] - [Route("umbraco/backoffice/product/{id?}")] - public string GetProduct(int? id) - { - if (id is not null) - { - return $"Monitor model {id}"; - } - return "Base model Monitor"; - } -} -``` - -## Using MemberAuthorizeAttribute - -To secure your controller based on front-end membership use the attribute: `Umbraco.Cms.Web.Common.Filters.UmbracoMemberAuthorize`. - -There are 3 parameters that can be supplied to control how the authorization works: - -```csharp -// Comma delimited list of allowed member types -string AllowType - -// Comma delimited list of allowed member groups -string AllowGroup - -// Comma delimited list of allowed member Ids -string AllowMembers -``` - -To allow all members, use the attribute without supplying any parameters. - -You can apply these attributes at the controller level or at the action level. - -**Examples:** - -This will only allow logged in members of type "Retailers" to access the GetAllProducts action: - -```csharp -public class ProductsController : UmbracoApiController -{ - [UmbracoMemberAuthorize("Retailers", "", "")] - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } -} -``` - -This will only allow member's belonging to the group VIP to access any actions on the controller: - -``` -[UmbracoMemberAuthorize("", "VIP", "")] -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } -} -``` - -This will only allow member's with Ids 1, 10 and 20 to access any actions on the controller: - -```csharp -[UmbracoMemberAuthorize("", "", "1,10,20")] -public class ProductsController : UmbracoApiController -{ - public IEnumerable GetAllProducts() - { - return new[] {"Table", "Chair", "Desk", "Computer"}; - } -} -``` diff --git a/10/umbraco-cms/reference/routing/umbraco-api-controllers/routing.md b/10/umbraco-cms/reference/routing/umbraco-api-controllers/routing.md deleted file mode 100644 index c4674d247a6..00000000000 --- a/10/umbraco-cms/reference/routing/umbraco-api-controllers/routing.md +++ /dev/null @@ -1,54 +0,0 @@ ---- - - -meta.Title: "Umbraco WebApi Routing & Urls" -description: "How api controllers are routed and how to retrieve their URLs" ---- - -# Routing & Urls - -_This section will describe how Umbraco Api controllers are routed and how to retrieve their URLs_ - -## Routing - -Like Surface Controllers in Umbraco, when you inherit from the base class `Umbraco.Cms.Web.Common.Controllers.UmbracoApiController` we will auto-route this controller so you don't have to worry about routing at all. - -All locally declared Umbraco api controllers will be routed under the url path of: - -~/Umbraco/Api/[YourControllerName] - -All plugin based Umbraco api controllers will be routed under the url path of: - -~/Umbraco/[YourAreaName]/[YourControllerName] - -* [More information on implementing these controllers](README.md). - -## Urls - -We've added some handy `UrlHelper` extension methods to help you retrieve the Url of your Umbraco Api controllers. The extension methods are found in the class: `Umbraco.Extensions.UrlHelperExtensions` so you'll need to ensure you have the namespace `Umbraco.Extensions` imported. You will also need to inject `UmbracoApiControllerTypeCollection`, if you want to use any of the overloads that require it. - -The method overloads are: - -```csharp -string GetUmbracoApiService(UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName) -string GetUmbracoApiService(UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, Expression> methodSelector) -string GetUmbracoApiService(UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName, Type apiControllerType) -string GetUmbracoApiService(string actionName, string controllerName) -string GetUmbracoApiService(string actionName, string controllerName, string area) -``` - -The most consistent way to retrieve a Url is to use your controller's type, and an expression to select the action. Example of retrieving a URL in a view: - -```csharp -@using RoutingDocs.ApiControllers -@inject Umbraco.Cms.Core.UmbracoApiControllerTypeCollection _controllers; - -@(Url.GetUmbracoApiService(_controllers, controller => controller.GetAllProducts())) -``` - -Generally a UrlHelper instance will be available on most base classes like Controllers and Views, and you shouldn't have to create it manually, but if you need to you can, by injecting `IUrlHelperFactory` and `IActionContextAccessor` and then use the factory like so: - -```C# -var urlHelper = _urlFactory.GetUrlHelper(_actionContextAccessor.ActionContext); -var url = urlHelper.GetUmbracoApiService("GetAllProducts", "Products"); -``` diff --git a/10/umbraco-cms/reference/routing/url-tracking.md b/10/umbraco-cms/reference/routing/url-tracking.md deleted file mode 100644 index 788f6286a58..00000000000 --- a/10/umbraco-cms/reference/routing/url-tracking.md +++ /dev/null @@ -1,44 +0,0 @@ ---- - - -meta.Title: "URL Redirect Management" -description: "URL redirect management in Umbraco" ---- - -# URL Redirect Management - -## User Overview - -Whenever a document is published, and this causes changes to its URL (and any of its descendants' URLs), Umbraco makes a note of the old URLs. Whenever an incoming request is served and the default content finders cannot find a matching published document, Umbraco checks whether the URL matches one of these saved URLs. If a match is found, Umbraco returns a "301 Redirect" response pointing to the new URL of the document. - -The URL Redirect Management functionality does not support rewriting "rules" (e.g. regular expressions), nor complex scenarios (e.g. changing the culture and hostnames configuration). There are already powerful solutions to deal with these types of situations, such as Microsoft's own [Url Rewrite](https://www.iis.net/downloads/microsoft/url-rewrite) module for IIS. Since netcore is decoupled from the webserver hosting it, your approach for URL rewriting, outside what Umbraco provide out of the box, will depend on what you use to host your solutions, but for more info on the IIS Url Rewrite module have a look at the [official documentation](https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/url-rewrite-module-configuration-reference). - -## Dashboard - -It is possible to list the redirect URLs via the *Redirect Url Management* dashboard in the *Content* section. This dashboard lists the original URL, new URL, and culture. It also allows you to delete a URL redirect. - -In addition, the dashboard can be used to disable or enable the 301 Redirect Management (via the `appsettings.json` configuration option described below - note that this requires an application restart to take effect). - -## Technical Overview - -Anytime a document is published and its corresponding *url segment* changes, Umbraco checks its URL (and all its descendants' URLs) for changes. For every URL that has changed, it creates (or updates) a row in the `umbracoRedirectUrl` table. Rows in this table contain: the old url, the create date, and the target content identifier, culture, and a url hash. - -Umbraco registers a new content finder, `ContentFinderByRedirectUrl`, which runs as a normal content finder after the other content finders. It looks for the incoming URL in the database table and, if found, computes the URL of the target document and returns a "301 Redirect". These redirects are considered "permanent". It's good to note that we explicitly set `no-cache` headers on these redirects so that when they change, browsers update the URL immediately. They are a "true" 301, however, and search engines will accept them as such. - -## Enable / Disable / Configure - -The 301 Redirect Management feature is enabled by default. - -It is possible to disable the feature entirely (both generating URLs in the database table, and running the content finder) by editing the `appsettings.json` file: - -```json -"Umbraco": { - "CMS": { - "WebRouting": { - "DisableRedirectUrlTracking": false - } - } -} -``` - -See [the web routing config reference](../configuration/webroutingsettings.md) for more configuration options diff --git a/10/umbraco-cms/reference/scheduling.md b/10/umbraco-cms/reference/scheduling.md deleted file mode 100644 index 7e17c785ae9..00000000000 --- a/10/umbraco-cms/reference/scheduling.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -description: "Use hosted services (RecurringHostedServiceBase) to run a background task in Umbraco CMS." ---- - -# Scheduling - -It is possible to run recurring code using a hosted service. Below is a complete example showing how to create and register a hosted service that will regularly empty out the recycle bin every five minutes. - -{% hint style="warning" %} -Be aware you may or may not want this hosted service code to run on all servers, if you are using Load Balancing with multiple servers, see [load balancing documentation](../fundamentals/setup/server-setup/load-balancing/) for more information -{% endhint %} - -## RecurringHostedService example - -```chsarp -using System; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.HostedServices; - -namespace Umbraco.Docs.Samples.Web.RecurringHostedService -{ - public class CleanUpYourRoom : RecurringHostedServiceBase - { - private readonly IRuntimeState _runtimeState; - private readonly IContentService _contentService; - private readonly IServerRoleAccessor _serverRoleAccessor; - private readonly IProfilingLogger _profilingLogger; - private readonly ILogger _logger; - private readonly IScopeProvider _scopeProvider; - - private static TimeSpan HowOftenWeRepeat => TimeSpan.FromMinutes(5); - private static TimeSpan DelayBeforeWeStart => TimeSpan.FromMinutes(1); - - public CleanUpYourRoom( - IRuntimeState runtimeState, - IContentService contentService, - IServerRoleAccessor serverRoleAccessor, - IProfilingLogger profilingLogger, - ILogger logger, - IScopeProvider scopeProvider) - : base(logger, HowOftenWeRepeat, DelayBeforeWeStart) - { - _runtimeState = runtimeState; - _contentService = contentService; - _serverRoleAccessor = serverRoleAccessor; - _profilingLogger = profilingLogger; - _logger = logger; - _scopeProvider = scopeProvider; - } - - public override Task PerformExecuteAsync(object state) - { - // Don't do anything if the site is not running. - if (_runtimeState.Level != RuntimeLevel.Run) - { - return Task.CompletedTask; - } - - // Wrap the three content service calls in a scope to do it all in one transaction. - using IScope scope = _scopeProvider.CreateScope(); - - int numberOfThingsInBin = _contentService.CountChildren(Constants.System.RecycleBinContent); - _logger.LogInformation("Go clean your room - {ServerRole}", _serverRoleAccessor.CurrentServerRole); - _logger.LogInformation("You have {NumberOfThingsInTheBin} items to clean", numberOfThingsInBin); - - if (_contentService.RecycleBinSmells()) - { - // Take out the trash - using (_profilingLogger.TraceDuration("Mum, I am emptying out the bin", - "It's all clean now")) - { - _contentService.EmptyRecycleBin(userId: -1); - } - } - - // Remember to complete the scope when done. - scope.Complete(); - return Task.CompletedTask; - } - } -} -``` - -{% hint style="info" %} -If you are using an Umbraco version before v9.4 you can't pass in an instance of `ILogger` in to the base constructor. See the code example below: - -``` -public CleanUpYourRoom( - ...) - : base(HowOftenWeRepeat, DelayBeforeWeStart) -{ - ... -} -``` -{% endhint %} - -### Registering with extension method - -First we need to create our extension method where we register the hosted service with `AddHostedService`: - -``` -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Docs.Samples.Web.RecurringHostedService -{ - public static class UmbracoBuilderHostedServiceExtensions - { - public static IUmbracoBuilder AddCustomHostedServices(this IUmbracoBuilder builder) - { - builder.Services.AddHostedService(); - return builder; - } - } -} -``` - -Now we can invoke it in the `ConfigureServices` method in `Startup.cs`: - -``` -public void ConfigureServices(IServiceCollection services) -{ -#pragma warning disable IDE0022 // Use expression body for methods - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddCustomHostedServices() // Register CleanUpYourRoom - .Build(); -#pragma warning restore IDE0022 // Use expression body for methods -} -``` - -### Registering with a composer - -All we need to do here is to create the composer where we register the hosted service with `AddHostedService`, which will be run automatically: - -``` -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Docs.Samples.Web.RecurringHostedService -{ - public class CleanUpYourRoomComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddHostedService(); - } - } -} -``` - -## RecurringHostedServiceBase - -This class provides the base class for any hosted service. - -You can override the `PerformExecuteAsync` method to implement the class. Hosted services are always run asynchronously. - -The `RecurringHostedServiceBase` is a base class that implements the netcore interface `IHostedService` and makes the task recurring, if you don't need your task to run recurringly you can implement `IHostedService` yourself, and register your hosted service in the same way. For more information about hosted services, take a look at the [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-5.0). - -## BackgroundTaskRunner Notifications - -In earlier versions of Umbraco, there were a series of events triggered by background tasks, with the switch to notifications this no longer exists, however, fear not, because you can publish any custom notification you desire from within your background task. For more information about creating and publishing your own custom notifications see: [Creating and Publishing Custom Notifications](notifications/creating-and-publishing-notifications.md) - -## Using ServerRoleAccessor - -In the example above you could add the following switch case at the beginning to help determine the server role & thus if you don't want to run code on that type of server you can exit out early. - -``` -// Do not run the code on subscribers or unknown role servers -// ONLY run for SchedulingPublisher server or Single server roles -switch (_serverRoleAccessor.CurrentServerRole) -{ - case ServerRole.Subscriber: - _logger.LogDebug("Does not run on subscriber servers."); - return Task.CompletedTask; // We return Task.CompletedTask to try again as the server role may change! - case ServerRole.Unknown: - _logger.LogDebug("Does not run on servers with unknown role."); - return Task.CompletedTask; // We return Task.CompletedTask to try again as the server role may change! -} -``` diff --git a/10/umbraco-cms/reference/searching/README.md b/10/umbraco-cms/reference/searching/README.md deleted file mode 100644 index 405bb956ddb..00000000000 --- a/10/umbraco-cms/reference/searching/README.md +++ /dev/null @@ -1,19 +0,0 @@ ---- - - ---- - -# Searching - -_Search in Umbraco is powered by Examine out of the box, which is a Lucene-based search and index engine for Umbraco. Umbraco provides everything required to have powerful and fast search up and running on your website. You can also extend or replace the available configuration to exactly match your requirements. This documentation focuses on the Examine implementation._ - -## [Examine](examine/) - -{% hint style="info" %} -Examine and Lucene are external parts used in Umbraco. When working with either of the two, we strongly recommend using their official documentation. - -- [Lucene](https://lucenenet.apache.org/) -- [Examine](https://shazwazza.github.io/Examine/) -{% endhint %} - -Understand how Examine works and walk through the many available options and settings in Umbraco. diff --git a/10/umbraco-cms/reference/searching/examine/README.md b/10/umbraco-cms/reference/searching/examine/README.md deleted file mode 100644 index ade8c11549f..00000000000 --- a/10/umbraco-cms/reference/searching/examine/README.md +++ /dev/null @@ -1,38 +0,0 @@ ---- - - ---- - -# Examine - -_Examine uses Lucene as its search and index engine. Searching using Examine with Lucene can be powerful and fast._ - -## What is Examine? - -The Examine documentation is found here [https://shazwazza.github.io/Examine/](https://shazwazza.github.io/Examine/) and the source code repository for Examine is here [https://github.com/Shazwazza/Examine](https://github.com/Shazwazza/Examine). - -Examine allows you to index and search data quickly. Examine is a library that sits on top of [Lucene.Net](https://lucenenet.apache.org/), a high-performance search engine library. Examine provides APIs to make searching and indexing as straightforward as possible. UmbracoExamine adds an extra layer to access Umbraco-specific APIs for indexing and searching content and media. - -Examine is provider based so it is extensible and allows you to configure your own custom indexes if required. The backoffice search in Umbraco also uses this same search engine, so you can trust that you're in good hands. - -## [Quick start](quick-start.md) - -Get up and running with Examine straight away with this quick start guide. - -## [Customizing indexes](indexing.md) - -Learn how to customize the built in Umbraco indexes and how to create your own Lucene indexes using Examine in Umbraco. - -## [PDF indexing and multisearchers](pdfindex-multisearcher.md) - -Learn how to index PDF files in Examine and how to create a multisearcher that searches through both the External Index and the Pdf Index. - -## [Examine Management in the backoffice](examine-management.md) - -Provides an overview of the available Examine functionality available directly within the Umbraco backoffice. - -Details about subscribing to Examine events which can provide a way to modify the data being indexed. - -## [API - Examine Manager](examine-manager.md) - -Describes the singleton object which exposes all of the index and search providers which are registered in the configuration of the Umbraco application. diff --git a/10/umbraco-cms/reference/searching/examine/examine-management.md b/10/umbraco-cms/reference/searching/examine/examine-management.md deleted file mode 100644 index 782c6cf725d..00000000000 --- a/10/umbraco-cms/reference/searching/examine/examine-management.md +++ /dev/null @@ -1,43 +0,0 @@ -# Examine Management - -_Provides an overview of the available Examine functionality available directly within the Umbraco backoffice_ - -## Overview - -The Umbraco backoffice allows you to view details about your Examine indexes and searchers - all in one place. You can see which fields are being indexed, rebuild the indexes if there's a problem, and test keywords to see what results would be returned. - -![Examine Management within the Developer section](images/overview-examine.png) - -The Examine Management section, accessible from within the Settings section, is split into two sections: Indexers and Searchers. - -## Indexers - -From the Indexers section, you can view details about each Examine index currently configured within your Umbraco installation. Clicking any of these indexes will show you additional options, each discussed below. - -### Index info - -This section allows you to see the list of properties on the index that you selected, including how many documents and fields are currently being stored. - -![Rebuild Index within Examine Management](images/External-indexes-v10.png) - -Within the Indexers it displays the details for the index provider as well. - -This can be useful to confirm the configuration that Umbraco is using and to ensure it is working as expected. This section also displays the full file path of the index itself. - -This section also provides the ability to rebuild the index, should this be required. Depending on how much content your website has, rebuilding the search indexes could take a while and affect the site performance temporarily, so it is not recommended to do this while the website is under high load. - -### Fields - -From here you can see the default system fields that are stored for each document within the search index. That includes the number of fields document, and the score which is calculated by Examine depending on how closely the individual results matched the search term. - -## Searchers - -From the Searchers section, you can view details about each Examine searcher currently configured within your Umbraco installation. Clicking any of these searchers will take you to a search page, where you can test out your search terms. - -You can see an example here how to configure an Examine searcher in the [Examine Multisearcher documentation](pdfindex-multisearcher.md#multi-index-searchers). - -### Search field - -![Search field for custom searcher within Examine Management](images/examine-management-search-field.png) - -The search field allows you to enter a search term and receive results back from the searcher in question. You can confirm if your query is working as expected. Matching results are returned in their raw format, with the score, document ID and Name being returned. The score is calculated by Examine depending on how closely the individual results matched the search term. diff --git a/10/umbraco-cms/reference/searching/examine/examine-manager.md b/10/umbraco-cms/reference/searching/examine/examine-manager.md deleted file mode 100644 index 1fdf75f13b1..00000000000 --- a/10/umbraco-cms/reference/searching/examine/examine-manager.md +++ /dev/null @@ -1,151 +0,0 @@ -# Examine Manager - -Accessing the singleton can be done by using dependency injection. - -In a class you can inject the IExamineManager interface: - -```csharp -using Examine; - -namespace MyCustomUmbracoSolution; - -public class MyClass -{ - private readonly IExamineManager _examineManager; - public MyClass(IExamineManager examineManager) - { - _examineManager = examineManager; - } -} -``` - -In a view the IExamineManager can be injected as well: - -```csharp -@inject IExamineManager ExamineManager; -``` - -This returns an active instance of the ExamineManager which exposes operations such as: - -* Default index & search providers -* Full collection of index & search providers -* All indexing and searching methods - -## Searching - -Important to note that the `Search` methods on the ExamineManager will call the Search methods of the **default** search provider specified in config. If you want to search using a specific provider, there are generally two approaches for this. - -If you want to use the searcher of a specific index, you should get the the searcher via the index: - -```csharp -@inherits UmbracoViewPage -@using Examine -@using Umbraco.Cms.Core -@inject IExamineManager ExamineManager -@{ - - // Get the search text from the query string - string query = Context.Request.Query["query"]; - - // Try to get the "ExternalIndex" from the Examine manager - if (ExamineManager.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out IIndex index)) - { - - // Search via the searcher of the index - ISearchResults searchResults = index.Searcher.Search(query); - - // Check whether the search revealed any results - if (searchResults.Any()) - { -
    - @foreach (ISearchResult result in searchResults) - { - - // Skip the result if the ID is null - if (result.Id is null) continue; - - // Skip the result if not found in the content cache - if (Umbraco.Content(result.Id) is not {} node) continue; - -
  • - @node.Name -
  • - - } -
- } - - } - -} -``` - -If you have configured a custom searcher that you wish to use instead, you can access the searcher directly via the `IExamineManager` instance: - -```csharp -bool canGetSearcher = ExamineManager.TryGetSearcher("MyCustomSearcher", out ISearcher searcher); -``` - -An example using a custom searcher is below: - -```csharp -@inherits UmbracoViewPage -@using Examine -@inject IExamineManager ExamineManager -@{ - - // Get the search text from the query string - string query = Context.Request.Query["query"]; - - // Try to get the "MyCustomSearcher" searcher - if (ExamineManager.TryGetSearcher("MyCustomSearcher", out ISearcher searcher)) - { - - // Search via the searcher - ISearchResults searchResults = searcher.Search(query); - - // Check whether the search revealed any results - if (searchResults.Any()) - { -
    - @foreach (ISearchResult result in searchResults) - { - - // Skip the result if the ID is null - if (result.Id is null) continue; - - // Skip the result if not found in the content cache - if (Umbraco.Content(result.Id) is not {} node) continue; - -
  • - @node.Name -
  • - - } -
- } - - } - -} -``` - -## Indexing - -When you wanna populate an index, you will need to use the `IExamineManager` and get the specific index. The build-in index names are all available as constants from the `Umbraco.Cms.Core.Constants.UmbracoIndexes` namespace - -```csharp -if (_examineManager.TryGetIndex(Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName, out IIndex index)) -{ - // Use index here -} -``` - -The indexing methods available on a single index are: - -```csharp -void DeleteFromIndex(IEnumerable itemIds); -void DeleteFromIndex(this IIndex index, string itemId); -void IndexExists(); -void IndexItems(IEnumerable values); -``` diff --git a/10/umbraco-cms/reference/searching/examine/images/External-indexes-v10.png b/10/umbraco-cms/reference/searching/examine/images/External-indexes-v10.png deleted file mode 100644 index 9e397730d7a..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/External-indexes-v10.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-home.png b/10/umbraco-cms/reference/searching/examine/images/examine-management-home.png deleted file mode 100644 index 7a4f82e8896..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-home.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-document (1).png b/10/umbraco-cms/reference/searching/examine/images/examine-management-product-document (1).png deleted file mode 100644 index 100222968ed..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-document (1).png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-document.png b/10/umbraco-cms/reference/searching/examine/images/examine-management-product-document.png deleted file mode 100644 index 100222968ed..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-document.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-index (1).png b/10/umbraco-cms/reference/searching/examine/images/examine-management-product-index (1).png deleted file mode 100644 index ee91e43bba0..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-index (1).png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-index.png b/10/umbraco-cms/reference/searching/examine/images/examine-management-product-index.png deleted file mode 100644 index ee91e43bba0..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-product-index.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-rebuild-index.png b/10/umbraco-cms/reference/searching/examine/images/examine-management-rebuild-index.png deleted file mode 100644 index db57b168b8a..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-rebuild-index.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-search-field.png b/10/umbraco-cms/reference/searching/examine/images/examine-management-search-field.png deleted file mode 100644 index b8bbb00d317..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-search-field.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/examine-management-search-tools.png b/10/umbraco-cms/reference/searching/examine/images/examine-management-search-tools.png deleted file mode 100644 index 6d451906c50..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/examine-management-search-tools.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/overview-examine.png b/10/umbraco-cms/reference/searching/examine/images/overview-examine.png deleted file mode 100644 index 0c243fc97cc..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/overview-examine.png and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/images/transforming-index-values.PNG b/10/umbraco-cms/reference/searching/examine/images/transforming-index-values.PNG deleted file mode 100644 index 49f1078e9ef..00000000000 Binary files a/10/umbraco-cms/reference/searching/examine/images/transforming-index-values.PNG and /dev/null differ diff --git a/10/umbraco-cms/reference/searching/examine/indexing.md b/10/umbraco-cms/reference/searching/examine/indexing.md deleted file mode 100644 index 99012a583eb..00000000000 --- a/10/umbraco-cms/reference/searching/examine/indexing.md +++ /dev/null @@ -1,486 +0,0 @@ ---- -description: >- - Learn how to build and customize the indexes that comes with your Umbraco - website. ---- - -# Custom indexing - -## Customizing the built in indexes - -You can modify the built-in indexes in the following ways: - -* [Events](https://shazwazza.github.io/Examine/articles/indexing.html#events) - giving you control over exactly what data goes into them and how the fields are configured -* Changing the field value types to change how values are stored in the index -* Changing the `IValueSetValidator` to change what goes into the index -* Take control of the entire index creation pipeline to change the implementation - -We can do all this by using the `ConfigureNamedOptions` pattern. - -## Creating a ConfigureOptions class - -We will start by creating a ConfigureExamineOptions class, that derives from `IConfigureNamedOptions`: - -```csharp -using Examine.Lucene; -using Microsoft.Extensions.Options; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ConfigureExternalIndexOptions : IConfigureNamedOptions -{ - public void Configure(string name, LuceneDirectoryIndexOptions options) - { - throw new System.NotImplementedException(); - } - - public void Configure(LuceneDirectoryIndexOptions options) - { - throw new System.NotImplementedException(); - } -} -``` - -{% hint style="info" %} -In this sample we are altering the external index and thus we name the class `ConfigureExternalIndexOptions`. If you are altering multiple indexes, it is recommended to have separate classes for each index - i.e. `ConfigureExternalIndexOptions` for the external index, `ConfigureInternalIndexOptions` for the internal index and so on. -{% endhint %} - -When using the `ConfigureNamedOptions` pattern, we have to register this in a composer for it to configure our indexes, this can be done like this: - -```csharp -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ExamineComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.Services.ConfigureOptions(); - } -} -``` - -### Changing field value types - -By default, Examine will store values into the Lucene index as "Full Text" fields, meaning the values will be indexed and analyzed for a textual search. However, if a field value is numerical, date/time, or another non-textual value type, you might want to change how the value is stored in the index. This will let you take advantage of some value type-specific search features such as numerical or date range. - -There is some documentation about this in the [Examine documentation](https://shazwazza.github.io/Examine/articles/configuration.html). - -The easiest way to modify how a field is configured is using the `ConfigureNamedOptions` pattern like so: - -```csharp -using Examine; -using Examine.Lucene; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ConfigureExternalIndexOptions : IConfigureNamedOptions -{ - public void Configure(string name, LuceneDirectoryIndexOptions options) - { - if (name.Equals(Constants.UmbracoIndexes.ExternalIndexName)) - { - options.FieldDefinitions.AddOrUpdate(new FieldDefinition("price", FieldDefinitionTypes.Double)); - } - } - - // Part of the interface, but does not need to be implemented for this. - public void Configure(LuceneDirectoryIndexOptions options) - { - throw new System.NotImplementedException(); - } -} -``` - -This will ensure that the `price` field in the index is treated as a `double` type (if the `price` field does not exist in the index, it is added). - -## Changing IValueSetValidator - -An `IValueSetValidator` is responsible for validating a `ValueSet` to see if it should be included in the index. For example, by default the validation process for the ExternalIndex checks if a `ValueSet` has a category type of either "media" or "content" (not member). If a `ValueSet` was passed to the ExternalIndex and it did not pass this requirement it would be ignored. - -The `IValueSetValidator` is also responsible for filtering the data in the `ValueSet`. For example, by default the validator for the MemberIndex will validate on all the default member properties, so an extra property "PhoneNumber", would not pass validation, and therefore not be included. - -The `IValueSetValidator` implementation for the built-in indexes, can be changed like this: - -```csharp -using Examine.Lucene; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Infrastructure.Examine; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ConfigureMemberIndexOptions : IConfigureNamedOptions -{ - public void Configure(string name, LuceneDirectoryIndexOptions options) - { - if (name.Equals(Constants.UmbracoIndexes.MembersIndexName)) - { - options.Validator = new MemberValueSetValidator(null, null, new[] {"email"}, null); - } - } - - // Part of the interface, but does not need to be implemented for this. - public void Configure(LuceneDirectoryIndexOptions options) - { - throw new System.NotImplementedException(); - } -} -``` - -{% hint style="info" %} -Remember to register `ConfigureMemberIndexOptions` in your composer. -{% endhint %} - -## Creating your own index - -The following example will show how to create an index that will only include nodes based on the document type _product_. - -{% hint style="info" %} -We always recommend that you use the existing built in ExternalIndex. You should then query based on the NodeTypeAlias instead of creating a new separate index based on that particular node type. However, should the need arise, the example below will show you how to do it. - -Take a look at our [Examine Quick Start](quick-start.md) to see some examples of how to search the ExternalIndex. -{% endhint %} - -To create this index we need five things: - -1. An `UmbracoExamineIndex` implementation that defines the index. -2. An `IConfigureNamedOptions` implementation that configures the index fields and options. -3. An `IValueSetBuilder` implementation that builds index value sets a piece of content. -4. An `IndexPopulator` implementation that populates the index with the value sets for all applicable content. -5. An `INotificationHandler` implementation that updates the index when content changes. -6. A composer that adds all these services to the runtime. - -### ProductIndex - -```csharp -using Examine.Lucene; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Examine; -using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ProductIndex : UmbracoExamineIndex -{ - public ProductIndex( - ILoggerFactory loggerFactory, - string name, - IOptionsMonitor indexOptions, - IHostingEnvironment hostingEnvironment, - IRuntimeState runtimeState) - : base(loggerFactory, - name, - indexOptions, - hostingEnvironment, - runtimeState) - { - } -} -``` - -### ConfigureProductIndexOptions - -```csharp -using Examine; -using Examine.Lucene; -using Lucene.Net.Analysis.Standard; -using Lucene.Net.Index; -using Lucene.Net.Util; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Configuration.Models; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ConfigureProductIndexOptions : IConfigureNamedOptions -{ - private readonly IOptions _settings; - - public ConfigureProductIndexOptions(IOptions settings) - => _settings = settings; - - public void Configure(string? name, LuceneDirectoryIndexOptions options) - { - if (name?.Equals("ProductIndex") is false) - { - return; - } - - options.Analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48); - - options.FieldDefinitions = new( - new("id", FieldDefinitionTypes.Integer), - new("name", FieldDefinitionTypes.FullText) - ); - - options.UnlockIndex = true; - - if (_settings.Value.LuceneDirectoryFactory == LuceneDirectoryFactory.SyncedTempFileSystemDirectoryFactory) - { - // if this directory factory is enabled then a snapshot deletion policy is required - options.IndexDeletionPolicy = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy()); - } - } - - // not used - public void Configure(LuceneDirectoryIndexOptions options) => throw new NotImplementedException(); -} -``` - -### ProductIndexValueSetBuilder - -```csharp -using Examine; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Infrastructure.Examine - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ProductIndexValueSetBuilder : IValueSetBuilder -{ - public IEnumerable GetValueSets(params IContent[] contents) - { - foreach (IContent content in contents.Where(CanAddToIndex)) - { - var indexValues = new Dictionary - { - // this is a special field used to display the content name in the Examine dashboard - [UmbracoExamineFieldNames.NodeNameFieldName] = content.Name!, - ["name"] = content.Name!, - // add the fields you want in the index - ["nodeName"] = content.Name!, - ["id"] = content.Id, - }; - - yield return new ValueSet(content.Id.ToString(), IndexTypes.Content, content.ContentType.Alias, indexValues); - } - } - - // filter out all content types except "product" - private bool CanAddToIndex(IContent content) => content.ContentType.Alias == "product"; -} -``` - -### ProductIndexPopulator - -```csharp -using Examine; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Examine; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ProductIndexPopulator : IndexPopulator -{ - private readonly IContentService _contentService; - private readonly ProductIndexValueSetBuilder _productIndexValueSetBuilder; - - public ProductIndexPopulator(IContentService contentService, ProductIndexValueSetBuilder productIndexValueSetBuilder) - { - _contentService = contentService; - _productIndexValueSetBuilder = productIndexValueSetBuilder; - RegisterIndex("ProductIndex"); - } - - protected override void PopulateIndexes(IReadOnlyList indexes) - { - foreach (IIndex index in indexes) - { - IContent[] roots = _contentService.GetRootContent().ToArray(); - index.IndexItems(_productIndexValueSetBuilder.GetValueSets(roots)); - - foreach (IContent root in roots) - { - const int pageSize = 10000; - var pageIndex = 0; - IContent[] descendants; - do - { - descendants = _contentService.GetPagedDescendants(root.Id, pageIndex, pageSize, out _).ToArray(); - IEnumerable valueSets = _productIndexValueSetBuilder.GetValueSets(descendants); - index.IndexItems(valueSets); - - pageIndex++; - } - while (descendants.Length == pageSize); - } - } - } -} -``` - -{% hint style="info" %} -This is only an example of how you could do indexing. In this example, we're indexing all content, both published and unpublished. - -In certain scenarios only published content should be added to the index. To achieve that, you will need to implement your own logic to filter out unpublished content. This can be somewhat tricky as the published state can vary throughout an entire structure of content nodes in the content tree. For inspiration on how to go about such filtering, you can look at the [ContentIndexPopulator in Umbraco](https://github.com/umbraco/Umbraco-CMS/blob/c878567633a6a3354c1414ccd130c9be518b25f0/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs#L115). -{% endhint %} - -### ProductIndexingNotificationHandler - -The index will only update its content when you manually trigger an index rebuild in the Examine dashboard. This is not always the desired behavior for a custom index. - -To update your index when content changes, you can use notification handlers. - -{% hint style="info" %} -The following handler class does not automatically update the descendant items of the modified content nodes, such as removing descendants of deleted content. If changes to the parent content item can affect its children or descendant items in your setup, please refer to the [UmbracoContentIndex.PerformDeleteFromIndex() in Umbraco](https://github.com/umbraco/Umbraco-CMS/blob/main/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs#L124-L153). Such logic should be applied when both removing and reindexing content items of type _product_. -{% endhint %} - -```csharp -using Examine; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Services.Changes; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure; -using Umbraco.Cms.Infrastructure.Search; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ProductIndexingNotificationHandler : INotificationHandler -{ - private readonly IRuntimeState _runtimeState; - private readonly IUmbracoIndexingHandler _umbracoIndexingHandler; - private readonly IExamineManager _examineManager; - private readonly IContentService _contentService; - private readonly ProductIndexValueSetBuilder _productIndexValueSetBuilder; - - public ProductIndexingNotificationHandler( - IRuntimeState runtimeState, - IUmbracoIndexingHandler umbracoIndexingHandler, - IExamineManager examineManager, - IContentService contentService, - ProductIndexValueSetBuilder productIndexValueSetBuilder) - { - _runtimeState = runtimeState; - _umbracoIndexingHandler = umbracoIndexingHandler; - _examineManager = examineManager; - _contentService = contentService; - _productIndexValueSetBuilder = productIndexValueSetBuilder; - } - - /// - /// Updates the index based on content changes. - /// - public void Handle(ContentCacheRefresherNotification notification) - { - if (NotificationHandlingIsDisabled()) - { - return; - } - - if (!_examineManager.TryGetIndex("ProductIndex", out IIndex? index)) - { - throw new InvalidOperationException("Could not obtain the product index"); - } - - ContentCacheRefresher.JsonPayload[] payloads = GetNotificationPayloads(notification); - - foreach (ContentCacheRefresher.JsonPayload payload in payloads) - { - // Remove - if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove)) - { - index.DeleteFromIndex(payload.Id.ToString()); - } - // Reindex - else if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshNode) || - payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch)) - { - IContent? content = _contentService.GetById(payload.Id); - if (content == null || content.Trashed) - { - index.DeleteFromIndex(payload.Id.ToString()); - continue; - } - - IEnumerable valueSets = _productIndexValueSetBuilder.GetValueSets(content); - index.IndexItems(valueSets); - } - } - } - - private bool NotificationHandlingIsDisabled() - { - // Only handle events when the site is running. - if (_runtimeState.Level != RuntimeLevel.Run) - { - return true; - } - - if (_umbracoIndexingHandler.Enabled == false) - { - return true; - } - - if (Suspendable.ExamineEvents.CanIndex == false) - { - return true; - } - - return false; - } - - private ContentCacheRefresher.JsonPayload[] GetNotificationPayloads(CacheRefresherNotification notification) - { - if (notification.MessageType != MessageType.RefreshByPayload || - notification.MessageObject is not ContentCacheRefresher.JsonPayload[] payloads) - { - throw new NotSupportedException(); - } - - return payloads; - } -} -``` - -{% hint style="info" %} -You can find further inspiration for implementing notification handlers (_for example, for media updates_) in the [UmbracoExamine.PDF package](https://github.com/umbraco/UmbracoExamine.PDF). -{% endhint %} - -### ExamineComposer - -```csharp -using Examine; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Infrastructure.Examine; - -namespace Umbraco.Docs.Samples.Web.CustomIndexing; - -public class ExamineComposer : IComposer -{ - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddExamineLuceneIndex("ProductIndex"); - - builder.Services.ConfigureOptions(); - - builder.Services.AddSingleton(); - - builder.Services.AddSingleton(); - - builder.AddNotificationHandler(); - } -} -``` - -{% hint style="info" %} -The order of these registrations matters. It is important to register your index with `AddExamineLuceneIndex` before calling `ConfigureOptions`. -{% endhint %} - -### Result - -![Custom product index](images/examine-management-product-index.png) - -![Product document]() diff --git a/10/umbraco-cms/reference/searching/examine/pdfindex-multisearcher.md b/10/umbraco-cms/reference/searching/examine/pdfindex-multisearcher.md deleted file mode 100644 index baed988b6a8..00000000000 --- a/10/umbraco-cms/reference/searching/examine/pdfindex-multisearcher.md +++ /dev/null @@ -1,58 +0,0 @@ -# PDF indexes and multisearchers - -If you want to index PDF files and search for them you will need to use the [UmbracoExamine.Pdf extension package](https://github.com/umbraco/UmbracoExamine.PDF). - -## Installation - -Install with NuGet: `dotnet add package Umbraco.ExaminePDF` - -This will create a new Examine index called "PDFIndex", which will appear in "Examine Management" dashboard under the "Settings" section. Using this index you can start searching the contents of any PDF files uploaded to the media section. - -![image](https://user-images.githubusercontent.com/7405322/189886089-d23b45c7-814b-4101-b143-31c5cd9fa655.png) - -## Multi-index searchers - -A multi-index searcher is a searcher that can search multiple indexes. This can be helpful when you for example want to search both the external and internal indexes. You can register a multi-index searcher with the ExamineManager on startup like: - -```csharp -using Examine; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using UmbracoExamine.PDF; - -namespace MySite.MyCustomIndex -{ - [ComposeAfter(typeof(ExaminePdfComposer))] - public class ExamineComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddExamineLuceneMultiSearcher("MultiSearcher", new[] {Constants.UmbracoIndexes.ExternalIndexName, PdfIndexConstants.PdfIndexName}); - } - } -} -``` - -With this approach, the multi-index searcher will show up in the "Examine Management" dashboard. - -![image](https://user-images.githubusercontent.com/7405322/189887744-af2d8e69-4807-4407-868d-b43e9fa9518d.png) - -The multi-index searcher can be resolved in code from the ExamineManager like this: - -```csharp -if (_examineManager.TryGetSearcher("MultiSearcher", out var searcher)) -{ - //TODO: use the `searcher` to search -} -``` - -{% hint style="warning" %} -The implementation of IPdfTextExtractor is PdfSharpTextExtractor in this library, which uses PDFSharp to extract the bytes to convert to text. That implementation doesn't deal well with Unicode text which means when some PDF files are read, the result will be 'junk' strings. - -It is certainly possible to replace the IPdfTextExtractor using your own composer like - -`composition.RegisterUnique();` - -The iTextSharp library deals with Unicode in a better way but is a paid for license. If you wish to use iTextSharp or another PDF library you can swap out the IPdfTextExtractor with your own implementation. -{% endhint %} diff --git a/10/umbraco-cms/reference/searching/examine/quick-start.md b/10/umbraco-cms/reference/searching/examine/quick-start.md deleted file mode 100644 index da25b47cb48..00000000000 --- a/10/umbraco-cms/reference/searching/examine/quick-start.md +++ /dev/null @@ -1,368 +0,0 @@ ---- - - ---- - -# quick-start - -## Quick start - -_This guide will help you get set up quickly using Examine with minimal configuration options. Umbraco ships Examine with 3 indexes: internal, external, and members. The internal index should not be used for searching when returning results on a public website because it includes content that has not been published yet. Instead, you can use the external index to get up and running._ - -### Performing a search - -{% hint style="info" %} -In the coming examples, the [Umbraco Starter Kit](https://our.umbraco.com/packages/starter-kits/the-starter-kit/) has been used, as it provides some example content that can be searched. Therefore, some of the examples below may require 'the setting up of templates, etc' if you follow the guide on your existing site. -{% endhint %} - -The starter kit comes with some Templates, Document Types, and content nodes created already. We will use some of these to set up a basic search system. This is a 'Quick Start' guide, as many more complex searches are possible with Examine. - -We will make it possible to 'search' on the _People_ page, by adding a search bar to the template page: `people.cshtml` - add the following form at the top of the template, but underneath the ` ---> -
-
- - -
-
-
-... -``` - -This will create a basic input field at the top of the page and make it post to the same people page when submitted along with the search term. - -#### Handling the search request - -The best practice for POST requests is to encapsulate the request handling in a controller. To do this we will leverage the concept of [route hijacking](../../routing/custom-controllers.md). - -Let's start by creating a `PeopleController` that derives from `RenderController` and add an `Index` method. - -{% hint style="info" %} -It is important to name our controller by the convention _`NameOfViewController`_. In our case the view is named People, so the controller is named `PeopleController`. -{% endhint %} - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; - -namespace MyStarterKitSite.Controllers; - -public class PeopleController : RenderController -{ - public PeopleController( - ILogger logger, - ICompositeViewEngine compositeViewEngine, - IUmbracoContextAccessor umbracoContextAccessor) - : base( - logger, - compositeViewEngine, - umbracoContextAccessor) - { - } - - public override IActionResult Index() - { - return CurrentTemplate(CurrentPage); - } -} -``` - -#### Adding a Service that handles our search logic - -To search anything from our controller, we first need to create a service that handles the actual search logic. We'll start by creating an interface for our service. - -```csharp -using System.Collections.Generic; -using Umbraco.Cms.Core.Models.PublishedContent; - -namespace MyStarterKitSite.Services; - -public interface ISearchService -{ - IEnumerable SearchContentNames(string query); -} -``` - -Now create a default implementation of the service interface. - -```csharp -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Web.UI.Services; - -namespace MyStarterKitSite.Services; - -public class SearchService : ISearchService -{ - public IEnumerable SearchContentNames(string query) => throw new NotImplementedException(); -} -``` - -And finally register the service in `Startup`. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - // ... (removed for abbreviation) - services.AddTransient(); -} -``` - -#### Examine Search Index - -To perform the search we will first need to get a reference to the particular Examine index that we want to search. Then we will use this index to access its corresponding `Searcher`. We use the `Searcher` to construct the query logic to execute and search the index. - -Umbraco ships with three indexes: - -* ExternalIndex - available to use for indexing published unprotected content. -* InternalIndex - which Umbraco's backoffice search uses. -* MembersIndex - which Umbraco's Membership implementation uses. - -[You can create your own indexes too](indexing.md) if you need to analyse text in a different language for example. - -The service `IExamineManager` is used to retrieve an Examine index by its 'alias', so we need to inject that service into our `SearchService`. - -```csharp -using System.Collections.Generic; -using Examine; -using Umbraco.Cms.Core.Models.PublishedContent; - -namespace MyStarterKitSite.Services; - -public class SearchServices : ISearchService -{ - private readonly IExamineManager _examineManager; - public SearchServices(IExamineManager examineManager) - { - _examineManager = examineManager; - } - public IEnumerable SearchContentNames(string query) => throw new NotImplementedException(); -} -``` - -#### Creating the Search Query - -With the `IExamineManager` injected in our `SearchService`, we can implement the `SearchContentNames` method. We do this using the `Searcher` for the Examine index 'ExternalIndex'. - -```csharp -IEnumerable ids = Array.Empty(); -if (!string.IsNullOrEmpty(query) && _examineManager.TryGetIndex("ExternalIndex", out IIndex? index)) -{ - ids = index - .Searcher - .CreateQuery("content") - .NodeTypeAlias("person") - .And() - .Field("nodeName", query) - .Execute() - .Select(x => x.Id); -} -``` - -{% hint style="info" %} -We reference the External index by its alias "ExternalIndex". Umbraco has a set of 'Constants' that refer to the indexes that can be more convenient to use `Constants.UmbracoIndexes`. So, in the example here we could have used `Constants.UmbracoIndexes.ExternalIndexName` instead of "ExternalIndex". -{% endhint %} - -The `Searcher` has a CreateQuery method, where you can choose to search content, media or members eg: - -```csharp -Searcher.CreateQuery("content") -``` - -From here you can see how we can chain together the logic to perform the search. In the example, we are searching all `content` using the `person` Document Type, where the `nodeName` is equal to the search term that was typed in the input bar. - -```csharp -Searcher.CreateQuery("content").NodeTypeAlias("person").And().Field("nodeName", searchTerm) -``` - -Calling `.Execute()` at the end of the query logic triggers the search and returns a set of matching search results, which we can loop through to get the IDs of the resulting content items. - -### Getting the content - -We want to retrieve the actual content from the IDs. For that, we need the `UmbracoHelper`, which must be injected into our service as well. The final implementation of `SearchService` then looks like this. - -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using Examine; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Web.Common; -using Umbraco.Extensions; - -namespace MyStarterKitSite.Services; - -public class SearchService : ISearchService -{ - private readonly IExamineManager _examineManager; - private readonly UmbracoHelper _umbracoHelper; - - public SearchService(IExamineManager examineManager, UmbracoHelper umbracoHelper) - { - _examineManager = examineManager; - _umbracoHelper = umbracoHelper; - } - - public IEnumerable SearchContentNames(string query) - { - IEnumerable ids = Array.Empty(); - if (!string.IsNullOrEmpty(query) && _examineManager.TryGetIndex("ExternalIndex", out IIndex? index)) - { - ids = index - .Searcher - .CreateQuery("content") - .NodeTypeAlias("person") - .And() - .Field("nodeName", query) - .Execute() - .Select(x => x.Id); - } - - foreach (var id in ids) - { - yield return _umbracoHelper.Content(id); - } - } -} -``` - -After getting the ids from our search, we then loop through the list and return the content. - -## Creating a custom view model - -We will now need a custom view model so that we can pass our search results to the view. Our view model needs to inherit from `PublishedContentWrapped` because our People view is expecting a model that is content. We then wrap the content and add the search data, all in a convenient view model. - -```csharp -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core.Models.PublishedContent; - -namespace MyStarterKitSite.Models; - -public class SearchViewModel : PublishedContentWrapped -{ - public SearchViewModel(IPublishedContent content, IPublishedValueFallback publishedValueFallback) - : base(content, publishedValueFallback) - { - } - - public IEnumerable SearchResults { get; set; } = Enumerable.Empty(); - public bool HasSearched { get; set; } -} -``` - -### Using the service and view model in the controller - -Now that we've created our service to handle the actual search logic, and our view model to pass the search results to the view, let's look at using them in the controller. We will want to update the `Index()` method to get out the query string from the request, then create a view model and populate the `SearchResults` property by using our service. - -```csharp -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using MyStarterKitSite.Models; -using MyStarterKitSite.Services; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.Controllers; - -namespace MyStarterKitSite.Controllers; - -public class PeopleController : RenderController -{ - private readonly IPublishedValueFallback _publishedValueFallback; - private readonly ISearchService _searchService; - - public PeopleController( - ILogger logger, - ICompositeViewEngine compositeViewEngine, - IUmbracoContextAccessor umbracoContextAccessor, - IPublishedValueFallback publishedValueFallback, - ISearchService searchService) - : base(logger, - compositeViewEngine, - umbracoContextAccessor) - { - _publishedValueFallback = publishedValueFallback; - _searchService = searchService; - } - - public override IActionResult Index() - { - // Get the queryString from the request - string queryString = HttpContext.Request.Query["query"]; - - // Create the view model and pass it to the view - SearchViewModel viewModel = new(CurrentPage!, _publishedValueFallback) - { - SearchResults = _searchService.SearchContentNames(queryString), - HasSearched = !string.IsNullOrEmpty(queryString), - }; - - return CurrentTemplate(viewModel); - } -} -``` - -### Updating the view to use the viewmodel - -The final thing we need to do is update the view to use our new view model. We do that by changing the `@inherits` line in the view. - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -``` - -Let's now use the view model to display the search results. We'll place them directly under the form we created earlier. - -```csharp -
- @if (Model.SearchResults.Any()) - { -
    - @foreach (var content in Model.SearchResults) - { -
  • - @content.Name -
  • - } -
- } - else if(Model.HasSearched) - { -

No results found

- } -
-``` - -## Different ways to query - -Examine has a lot of different ways to query data. Building upon the example from before, here are a few other searches that can be done to get different data: - -#### Search through all nodes - -Let's say you want to search through **all content nodes** by their **file names**. You could amend the query from before like this: - -```csharp -Searcher.CreateQuery("content").Field("nodeName", searchTerm).Execute(); -``` - -#### Search using Lucene queries - -To do the search like above, but only use Lucene to query, amend the query from before like this: - -```csharp -Searcher.CreateQuery().NativeQuery("+__IndexType:content +nodeName:" + searchTerm).Execute(); -``` - -#### Search children of a specific node - -To search through **all child nodes of a specific node** by their **bodyText property**, amend the query from before like this: - -```csharp -Searcher.CreateQuery("content").ParentId(1105).And().Field("bodyText", searchTerm).Execute(); -``` diff --git a/10/umbraco-cms/reference/security/README.md b/10/umbraco-cms/reference/security/README.md deleted file mode 100644 index 0d82f2a4f29..00000000000 --- a/10/umbraco-cms/reference/security/README.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -description: >- - This section includes information on Umbraco security, its various security - options and configuring how authentication & authorization works in Umbraco ---- - -# Security - -In this article, you will find everything you need regarding security within Umbraco. - -## [The Umbraco Trust Center (external)](https://umbraco.com/about-us/trust-center/) - -On our main website, we have a dedicated security section which provides all the details you need to know about security within the Umbraco CMS. This includes how to report a vulnerability. - -## [SSL/HTTPS](ssl-https.md) - -We highly encourage the use of HTTPS on Umbraco websites, especially in production environments. By using HTTPS you greatly improve the security of your website. - -In the "Use HTTPS" article you can learn more about how to use HTTPS and how to set it up. - -## [Security Settings](security-settings.md) - -Learn which password settings that can be configured in Umbraco. - -## [Security Hardening](security-hardening.md) - -Learn about how to harden the security on your Umbraco website to secure it even further. - -## [Security on Umbraco Cloud](https://docs.umbraco.com/umbraco-cloud/security) - -When your project is hosted on Umbraco Cloud, you might be interested in more details about the security of the hosting. This information can be found in the Umbraco Cloud FAQs section of the documentation. - -## [Backoffice users and website members (external)](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) - -Authentication for backoffice users and website members in Umbraco uses [ASP.NET Core Identity](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) which is a flexible and extendable framework for authentication. - -Out of the box Umbraco ships with a custom ASP.NET Core Identity implementation which uses Umbraco's database data. Normally this is fine for most Umbraco developers, but in some cases the authentication process needs to be customized. - -### [External login providers](external-login-providers.md) - -The Umbraco users and members supports external login providers (OAuth) for performing authentication of your users/members. This could be any OpenIDConnect provider such as Entra ID/Azure Active Directory, Identity Server, Google or Facebook. - -### [Two-factor authentication](two-factor-authentication.md) - -The Umbraco members supports a two-factor authentication (2FA) abstraction for implementing a 2FA provider of your choice. This could be any Time-based One-time Password (TOTP) Algorithm, including Microsoft and Google Authenticator Apps - -### [BackOfficeUserManager and Notifications](backofficeusermanager-and-notifications.md) - -The [`BackOfficeUserManager`](backofficeusermanager-and-notifications.md) is the ASP.NET Core Identity [UserManager](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1) implementation in Umbraco. It exposes APIs for working with Umbraco Users via the ASP.NET Core Identity including password handling. - -### [Custom password check](custom-password-check.md) - -In most cases [External login providers (OAuth)](external-login-providers.md) will meet the needs of most users when needing to authenticate with external resources but in some cases you may need to only change how the username and password credentials are checked. - -This is typically a legacy approach to validating credentials with external resources but it is possible. - -You are able to check the username and password against your own credentials store by implementing a [`IBackOfficeUserPasswordChecker`](custom-password-check.md). - -## [Sensitive data on members](sensitive-data-on-members.md) - -Marking fields as **sensitive** will hide the data in those fields for backoffice users that do not have permission to view personal data of members. - -Learn more about this in the [Sensitive Data](sensitive-data-on-members.md) article. - -## [Setup Umbraco for a FIPS Compliant Server](setup-umbraco-for-a-fips-server.md) - -How to configure Umbraco to run on a FIPS compliant server. - -## [Reset admin password](reset-admin-password.md) - -Use this guide to [reset the password of the "admin" user](reset-admin-password.md). - -If you need to reset accounts of every other user while you still have administrative action, check this "[reset normal user password](password-reset.md)" article. - -## Other articles related to security - -* [Routing requirements for backoffice authentication](../routing/authorized.md) -* [Health Checks](../../extending/health-check/) -* [Consent Service](../management/services/consentservice.md) diff --git a/10/umbraco-cms/reference/security/auto-linking.md b/10/umbraco-cms/reference/security/auto-linking.md deleted file mode 100644 index 5708d3402c6..00000000000 --- a/10/umbraco-cms/reference/security/auto-linking.md +++ /dev/null @@ -1,356 +0,0 @@ -# Linking External Login Provider accounts - -Traditionally when using [External login providers (OAuth)](external-login-providers.md), a backoffice user or website member will need to exist first and then that user can link their user account to an external login provider in the backoffice or edit profile page. - -In many cases, however, the external login provider you install will be the source of truth for all of your users. - -In this case, you will want to provide a Single Sign On (SSO) approach to logging in. This would enable the creating of user accounts on the external login provider and then automatically give them access to Umbraco. This is called auto-Linking. - -## Configure External Login provider - -To enable auto linking you have to implement a custom named configuration of `BackOfficeExternalLoginProviderOptions` or `MemberExternalLoginProviderOptions` for users or members, respectively. - -### Example for users - -_This example shows connection to an Open ID Connect Service such as_ [_IdentityServer4_](https://github.com/IdentityServer/IdentityServer4) _or_ [_OpenIDDict_](https://github.com/openiddict/openiddict-core) - -You can first create a `OpenIdConnectBackOfficeExternalLoginProviderOptions.cs` file which configures the options like - -```Csharp -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Web.BackOffice.Security; - -namespace Umbraco9 -{ - public class OpenIdConnectBackOfficeExternalLoginProviderOptions : IConfigureNamedOptions - { - public const string SchemeName = "OpenIdConnect"; - public void Configure(string name, BackOfficeExternalLoginProviderOptions options) - { - if (name != "Umbraco." + SchemeName) - { - return; - } - - Configure(options); - } - - public void Configure(BackOfficeExternalLoginProviderOptions options) - { - options.ButtonStyle = "btn-danger"; - options.Icon = "fa fa-cloud"; - options.AutoLinkOptions = new ExternalSignInAutoLinkOptions( - // must be true for auto-linking to be enabled - autoLinkExternalAccount: true, - - // Optionally specify default user group, else - // assign in the OnAutoLinking callback - // (default is editor) - defaultUserGroups: new[] { Constants.Security.EditorGroupAlias }, - - // Optionally specify the default culture to create - // the user as. If null it will use the default - // culture defined in the web.config, or it can - // be dynamically assigned in the OnAutoLinking - // callback. - - defaultCulture: null, - // Optionally you can disable the ability to link/unlink - // manually from within the back office. Set this to false - // if you don't want the user to unlink from this external - // provider. - allowManualLinking: false - ) - { - // Optional callback - OnAutoLinking = (autoLinkUser, loginInfo) => - { - // You can customize the user before it's linked. - // i.e. Modify the user's groups based on the Claims returned - // in the externalLogin info - }, - OnExternalLogin = (user, loginInfo) => - { - // You can customize the user before it's saved whenever they have - // logged in with the external provider. - // i.e. Sync the user's name based on the Claims returned - // in the externalLogin info - - return true; //returns a boolean indicating if sign in should continue or not. - } - }; - - // Optionally you can disable the ability for users - // to login with a username/password. If this is set - // to true, it will disable username/password login - // even if there are other external login providers installed. - options.DenyLocalLogin = false; - - // Optionally choose to automatically redirect to the - // external login provider so the user doesn't have - // to click the login button. This is - options.AutoRedirectLoginToExternalProvider = false; - } - } -} -``` - -Additionally, there are more advanced properties for `BackOfficeExternalLoginProviderOptions`: - -* `BackOfficeExternalLoginProviderOptions.CustomBackOfficeView` - * Allows for specifying a custom angular HTML view that will render in place of the default external login button. The purpose of this is in case you want to completely change the UI but also in these circumstances: - * You want to display something different where external login providers are listed: in the login screen vs the backoffice panel vs on the logged-out screen. This same view will render in all of these cases but you can use the current route parameters to customize what is shown. - * You want to change how the button interacts with the external login provider. For example, instead of having the site redirect on button-click, you want to open a popup window to load the external login provider. - * The path is a virtual path, for example: `"~/App_Plugins/MyPlugin/BackOffice/my-external-login.html"` - * When specifying this view it is 100% up to your angular view and affiliated angular controller to perform all required logic. - -To register this configuration class, you can call the following from your `startup.cs`: - -```Csharp -services.ConfigureOptions(); -``` - -We recommend to create an extension method on the `IUmbracoBuilder`, to add the Open Id Connect Authentication, like this This extension can also handle the configuration of `OpenIdConnectBackOfficeExternalLoginProviderOptions`: - -```Csharp -public static IUmbracoBuilder AddOpenIdConnectAuthentication(this IUmbracoBuilder builder) -{ - // Register OpenIdConnectBackOfficeExternalLoginProviderOptions here rather than require it in startup - builder.Services.ConfigureOptions(); - - builder.AddBackOfficeExternalLogins(logins => - { - logins.AddBackOfficeLogin( - backOfficeAuthenticationBuilder => - { - backOfficeAuthenticationBuilder.AddOpenIdConnect( - // The scheme must be set with this method to work for the back office - backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName), - options => - { - // use cookies - options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - // pass configured options along - options.Authority = "https://localhost:5000"; - options.ClientId = "YOURCLIENTID"; - options.ClientSecret = "YOURCLIENTSECRET"; - // Use the authorization code flow - options.ResponseType = OpenIdConnectResponseType.Code; - options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet; - // map claims - options.TokenValidationParameters.NameClaimType = "name"; - options.TokenValidationParameters.RoleClaimType = "role"; - - - options.RequireHttpsMetadata = true; - options.GetClaimsFromUserInfoEndpoint = true; - options.SaveTokens = true; - // add scopes - options.Scope.Add("openid"); - options.Scope.Add("email"); - options.Scope.Add("roles"); - options.UsePkce = true; - }); - }); - }); - return builder; -} -``` - -Finally this extension can also be called from the `Startup.cs` like the example below: - -```Csharp -services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddOpenIdConnectAuthentication() - .Build(); -``` - -{% hint style="info" %} -For some providers, it doesn't make sense to use auto-linking. This is especially true for public providers such as Google or Facebook. In those cases, it would mean that anyone who has a Google or Facebook account can log into your site. For public providers such as this, if auto-linking was needed you would need to limit the access by domain or other information provided in the Claims using the options/callbacks specified in those provider's authentication options. -{% endhint %} - -### Example for members - -The way to implement auto linking for members is fairly similar to how it is for users. The main difference is the UI, where Umbraco do not have a fixed login page for members. Instead, Umbraco ships with some Partial Macro Snippets for `Login` and `EditProfile` that contains handling of Login and manual linking of the configured external member providers. - -When auto-linking is enabled, only the `Login` snippet is relevant as users do not have to register before. - -The following example will show how to use Google and external login provider. You can first create a `GoogleMemberExternalLoginProviderOptions.cs` file which configures the options like - -```Csharp -using System; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Web.BackOffice.Security; - -namespace Umbraco9 -{ - public class GoogleMemberExternalLoginProviderOptions : IConfigureNamedOptions - { - public const string SchemeName = "Google"; - - public void Configure(string name, MemberExternalLoginProviderOptions options) - { - if (name != Constants.Security.MemberExternalAuthenticationTypePrefix + SchemeName) - { - return; - } - - Configure(options); - } - - public void Configure(MemberExternalLoginProviderOptions options) => - options.AutoLinkOptions = new MemberExternalSignInAutoLinkOptions( - // Must be true for auto-linking to be enabled - autoLinkExternalAccount: true, - - // Optionally specify the default culture to create - // the user as. If null it will use the default - // culture defined in the web.config, or it can - // be dynamically assigned in the OnAutoLinking - // callback. - defaultCulture: null, - - // Optionally specify the default "IsApprove" status. Must be true for auto-linking. - defaultIsApproved:true, - - // Optionally specify the member type alias. Default is "Member" - defaultMemberTypeAlias:"Member", - - // Optionally specify the member groups names to add the auto-linking user to. - defaultMemberGroups: Array.Empty() - ) - { - // Optional callback - OnAutoLinking = (autoLinkUser, loginInfo) => - { - // You can customize the member before it's linked. - // i.e. Modify the member's groups based on the Claims returned - // in the externalLogin info - }, - OnExternalLogin = (user, loginInfo) => - { - // You can customize the member before it's saved whenever they have - // logged in with the external provider. - // i.e. Sync the member's name based on the Claims returned - // in the externalLogin info - - return true; //returns a boolean indicating if sign in should continue or not. - } - }; - } -} -``` - -To register this configuration class, you can call the following from your `startup.cs`: - -```Csharp -services.ConfigureOptions(); -``` - -Like for users, we recommend creating an extension method on the `IUmbracoBuilder`, to add the Google Authentication, like this. This extension can also handle the configuration of `GoogleMemberExternalLoginProviderOptions`: - -```Csharp -public static IUmbracoBuilder AddMemberGoogleAuthentication(this IUmbracoBuilder builder) -{ - // Register GoogleMemberExternalLoginProviderOptions here rather than require it in startup - builder.Services.ConfigureOptions(); - - builder.AddMemberExternalLogins(logins => - { - logins.AddMemberLogin( - memberAuthenticationBuilder => - { - memberAuthenticationBuilder.AddGoogle( - // The scheme must be set with this method to work for the Umbraco members - memberAuthenticationBuilder.SchemeForMembers(GoogleMemberExternalLoginProviderOptions.SchemeName), - options => - { - options.ClientId = "YOURCLIENTID"; - options.ClientSecret = "YOURCLIENTSECRET"; - }); - }); - }); - return builder; -} -``` - -Finally this extension can also be called from the `Startup.cs` like the example below: - -```Csharp -services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddMemberGoogleAuthentication() - .Build(); -``` - -{% hint style="info" %} -Auto-linking only makes sense if you have a public member registration anyway or the external provider does not have public account creation. -{% endhint %} - -## Local logins - -If you have configured auto-linking, then any auto-linked user or member will have an empty password assigned and they will not be able to log in locally (via username and password). In order to log in locally, they will have to assign a password to their account in the backoffice or the edit profile page. - -For users only, if the `DenyLocalLogin` option is enabled, then all password changing functionality in the backoffice is also disabled and local login is not possible. - -## Transfering Claims from External identities - -In some cases you may want to flow a Claim returned in your external login provider to the Umbraco backoffice identity's Claims (the authentication cookie). This can be done during the `OnAutoLinking` and `OnExternalLogin`. - -Reason for this could be to store the external login provider user ID into the backoffice identity cookie. That way it can be retrieved on each request in order to look up some data in another system that needs the current user id from the external login provider. - -{% hint style="warning" %} -Do not flow large amounts of data into the backoffice identity because this information is stored into the backoffice authentication cookie and cookie limits will apply. Data like JWT tokens need to be [persisted](auto-linking.md#storing-external-login-provider-data) somewhere to be looked up and not stored within the backoffice identity itself. -{% endhint %} - -### Example - -_This is a very simplistic example for brevity, no null checks, etc..._ - -```Csharp -OnAutoLinking = (user, loginInfo) => { - // You can customize the user before it's linked. - // i.e. Modify the user's groups based on the Claims returned - // in the externalLogin info - var extClaim = externalLogin - .Principal - .FindFirst("MyClaim"); - user.Claims.Add(new IdentityUserClaim - { - ClaimType = extClaim.Type, - ClaimValue = extClaim.Value, - UserId = user.Id - }); -}, -OnExternalLogin = (user, loginInfo) => { - // You can customize the user before it's saved whenever they have - // logged in with the external provider. - // i.e. Sync the user's name based on the Claims returned - // in the externalLogin info - var extClaim = externalLogin - .Principal - .FindFirst("MyClaim"); - user.Claims.Add(new IdentityUserClaim - { - ClaimType = extClaim.Type, - ClaimValue = extClaim.Value, - UserId = user.Id - }); - return true; -} -``` - -## Storing external login provider data - -In some cases, you may need to persist data from your external login provider like Access Tokens, etc. You can persist this data to the affiliated user's external login data via the `IExternalLoginWithKeyService`. The `void Save(Guid userOrMemberKey,IEnumerable tokens)` overload takes a new model of type `IEnumerable`. `IExternalLogin` contains a property called `UserData`. This is a blob text column so can store any arbitrary data for the external login provider. - -{% hint style="info" %} -Be aware that the local Umbraco user must already exist and be linked to the external login provider before data can be stored here. In cases where auto-linking occurs and the backoffice user isn't yet created, you will most likely need to store this data in memory. First, during auto-linking and then persist this data to the service once the user is linked and created. -{% endhint %} diff --git a/10/umbraco-cms/reference/security/backofficeusermanager-and-notifications.md b/10/umbraco-cms/reference/security/backofficeusermanager-and-notifications.md deleted file mode 100644 index 068becbfbe6..00000000000 --- a/10/umbraco-cms/reference/security/backofficeusermanager-and-notifications.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -meta.Title: BackOfficeUserManager and Notifications -description: >- - The BackOfficeUserManager is the ASP.NET Core Identity UserManager - implementation in Umbraco. It exposes APIs for working with Umbraco User's via - the ASP.NET Core Identity including password handling. ---- - -# BackOfficeUserManager and Events - -The `BackOfficeUserManager` is the ASP.NET Core Identity [UserManager](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1) implementation in Umbraco. It exposes APIs for working with Umbraco Users via the ASP.NET Core Identity including password handling. - -## Extending - -The BackOfficeUserManager can be replaced during startup in order to use your own implementation. This may be required if you want to extend the functionality of the BackOfficeUserManager for things like supporting two-factor authentication(2FA). - -### Example - -You can replace the BackOfficeUserManager in the startup class by using the `SetBackOfficeUserManager` extension on the `IUmbracoBuilder`. - -```csharp -public class Startup -{ - ... - public void ConfigureServices(IServiceCollection services) - { - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .SetBackOfficeUserManager() - .Build(); - } - ... -} -``` - -You can then implement your custom `BackOfficeUserManager`, like this. Note the constructor minimum needs to inject what is required for the base `BackOfficeUserManager` class: - -```csharp - public class CustomBackOfficeUserManager : BackOfficeUserManager -{ - public CustomBackOfficeUserManager( - IIpResolver ipResolver, - IUserStore store, - IOptions optionsAccessor, - IPasswordHasher passwordHasher, - IEnumerable> userValidators, - IEnumerable> passwordValidators, - BackOfficeErrorDescriber errors, - IServiceProvider services, - IHttpContextAccessor httpContextAccessor, - ILogger logger, - IOptions passwordConfiguration, - IEventAggregator eventAggregator, - IBackOfficeUserPasswordChecker backOfficeUserPasswordChecker) - : base( - ipResolver, - store, - optionsAccessor, - passwordHasher, - userValidators, - passwordValidators, - errors, - services, - httpContextAccessor, - logger, - passwordConfiguration, - eventAggregator, - backOfficeUserPasswordChecker) - { - } - - //Override whatever you need, e.g. SupportsUserTwoFactor. - public override bool SupportsUserTwoFactor => false; -} -``` - -## Notifications - -There are [many notifications](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Web.Common.Security.BackOfficeUserManager.html) you can handle on the `BackOfficeUserManager`. Internally these are mainly used for auditing but there are some that allow you to customize some workflows: - -* `SendEmailNotification` - * This is a generic notification but it has a property `EmailType` that specify the email type. This type can be `UserInvite`. In that case, it allows you to take control over how a user in the backoffice is invited. This might be handy if you are using an [External Login Provider](external-login-providers.md) that has the `DenyLocalLogin` option assigned and you still want to have the user invite functionality available. In this setup, all of your users are controlled by your external login provider so you would need to handle the user invite flow yourself by using this event and inviting the user via your external provider. If you are using this event to replace the default functionality you will need to tell Umbraco that you've handled the invite by calling the `SendEmailNotification.HandleEmail()` method.) -* `UserLogoutSuccessNotification` - * This is specifically used if you have an [External Login Provider](external-login-providers.md) in use and you want to log out of that external provider when the user is logged out of the backoffice (that is log out of everywhere). The notification has a property `SignOutRedirectUrl`. If this property is assigned then Umbraco will redirect to that URL upon successful backoffice sign out in order to sign the user out of the external login provider. diff --git a/10/umbraco-cms/reference/security/cookies.md b/10/umbraco-cms/reference/security/cookies.md deleted file mode 100644 index c2eacaac1ce..00000000000 --- a/10/umbraco-cms/reference/security/cookies.md +++ /dev/null @@ -1,31 +0,0 @@ -# Cookies - -The cookies listed in this article are required only for accessing the Backoffice. You can include these in your own cookie policy, if you wish. - -## Necessary Cookies - -The below cookies are necessary for accessing the Umbraco Backoffice and functioning of the website. They allow you to enjoy the contents and services you request. - -| Name | Purpose | Expiration | -| -------------------------- | ----------------------------------------------------------------------------------------------------------------- | ---------- | -| UMB\_PREVIEW | Allows a previewed page to act as a published page only on the browser which has initialized previewing. | Session | -| UMB-WEBSITE-PREVIEW-ACCEPT | Client-side cookie that determines whether the user has accepted to be in Preview Mode when visiting the website. | Session | -| umb\_installId | Used to store the Umbraco software installer id. | Session | -| UMB\_UPDCHK | Enables your system to check for the Umbraco software updates. | Session | -| UMB-XSRF-V | Used to store the backoffice antiforgery token validation value. | Session | -| UMB-XSRF-TOKEN | Set for angular to pass in to the header value for "X-UMB-XSRF-TOKEN" | Session | -| TwoFactorRememberBrowser | Default authentication type used for storing that 2FA is not needed on next login | Session | -| UMB\_SESSION | Preserves the visitor's session state across page requests. | Session | - -The `UMB_SESSION` cookie is secure if you are using HTTPS pages. However, if you wish to secure the cookie in your code, add the following in the `Program.cs` file after `Build();` - -```cs -services.AddSession(options => - { - options.Cookie.Name = "UMB_SESSION"; - options.Cookie.HttpOnly = true; - options.Cookie.SecurePolicy = CookieSecurePolicy.Always; - }); -``` - -For information on the rest of the cookies, see the [Constants-Web.cs](https://github.com/umbraco/Umbraco-CMS/blob/main/src/Umbraco.Core/Constants-Web.cs) file on GitHub. diff --git a/10/umbraco-cms/reference/security/custom-password-check.md b/10/umbraco-cms/reference/security/custom-password-check.md deleted file mode 100644 index 502ef62c08d..00000000000 --- a/10/umbraco-cms/reference/security/custom-password-check.md +++ /dev/null @@ -1,50 +0,0 @@ -# Replacing the basic username/password check - -Having the ability to replace the logic to validate a username and password against a custom data store is important to some developers. Normally in ASP.Net Core Identity this would require you to override the `UmbracoBackOfficeUserManager.CheckPasswordAsync` implementation and then replace the `UmbracoBackOfficeUserManager` with your own class during startup. Since this is a common task we've made this process a lot easier with an interface called `IBackOfficeUserPasswordChecker`. - -Here are the steps to specify your own logic for validating a username and password for the backoffice: - -1. Create an implementation of `Umbraco.Cms.Core.Security.IBackOfficeUserPasswordChecker` - - * There is one method in this interface: `Task CheckPasswordAsync(BackOfficeIdentityUser user, string password);` - * The result of this method can be 3 things: - * ValidCredentials = The credentials entered are valid and the authorization should proceed - * InvalidCredentials = The credentials entered are not valid and the authorization process should return an error - * FallbackToDefaultChecker = This is an optional result which can be used to fallback to Umbraco's default authorization process if the credentials could not be verified by your own custom implementation - - For example, to always allow login when the user enters the password `test` you could do: - - ```C# - using System.Threading.Tasks; - using Umbraco.Core.Models.Identity; - using Umbraco.Core.Security; - - namespace MyNamespace - { - public class MyPasswordChecker : IBackOfficeUserPasswordChecker - { - public Task CheckPasswordAsync(BackOfficeIdentityUser user, string password) - { - var result = (password == "test") - ? Task.FromResult(BackOfficeUserPasswordCheckerResult.ValidCredentials) - : Task.FromResult(BackOfficeUserPasswordCheckerResult.InvalidCredentials); - - return result; - } - } - } - ``` -2. Register the `MyPasswordChecker` in your `Startup.ConfigureServices` method: - - ```C# - public void ConfigureServices(IServiceCollection services) - { - ... - - services.AddUnique(); - } - ``` - -{% hint style="info" %} -If the username entered in the login screen does not exist in Umbraco, then `MyPasswordChecker()` does not run. Instead, Umbraco will immediately fall back to its internal checks, which is the default Umbraco behavior. -{% endhint %} diff --git a/10/umbraco-cms/reference/security/external-login-providers.md b/10/umbraco-cms/reference/security/external-login-providers.md deleted file mode 100644 index 1d056e731e3..00000000000 --- a/10/umbraco-cms/reference/security/external-login-providers.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -versionFrom: 9.3.0 -keywords: oauth, security -meta.Title: External login providers -description: >- - Umbraco supports supports external login providers (OAuth) for performing - authentication of your users and members. This could be any OpenIDConnect - provider such as Azure Active Directory, Identity Se ---- - -# External login providers - -Both the Umbraco backoffice users and website members supports external login providers (OAuth) for performing authentication of your users or members. This could be any OpenIDConnect provider such as Entra ID/Azure Active Directory, Identity Server, Google or Facebook. - -Unlike previous major releases of Umbraco the use of Identity Extensions package is no longer required. - -Install an appropriate nuget package for the provider you wish to use. Some popular ones found in Nuget include: - -* [Google](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Google) -* [Facebook](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Facebook) -* [Microsoft](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.MicrosoftAccount/) -* [Twitter](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Twitter/3.0.0) -* [Open ID Connect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect) -* [Others](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/other-logins?view=aspnetcore-5.0) - -{% hint style="info" %} -**Try it out** - -* This community-created package with a complete Umbraco solution incl. an SQLite database demonstrates how OpenID Connect can be used: [Umbraco OpenIdConnect Example](https://github.com/jbreuer/Umbraco-OpenIdConnect-Example). -* This community-created package will allow you to automatically create Umbraco user accounts for users in your directory. This will then associate the Umbraco users with groups based on their AD group: [Umbraco.Community.AzureSSO](https://github.com/Gibe/Umbraco.Community.AzureSSO). - -It is great for testing and for trying out the implementation before building it into your own project. -{% endhint %} - -To configure the provider create a new static extension class for your provider and configure a custom named options like `GoogleBackOfficeExternalLoginProviderOptions` described in details in the [auto linking](auto-linking.md) section. The code example below shows how the configuration for Google Authentication can be done. You can find an example for how this can be done with Microsoft in the [Authenticating on the Umbraco backoffice with Active Directory credentials](../../tutorials/authenticate-with-active-directory.md) article. - -``` -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Extensions; -using Umbraco.Cms.Web.BackOffice.Security; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Configuration; - -namespace Umbraco.Cms.Web.UI.NetCore.Configuration -{ - public static class GoogleBackofficeAuthenticationExtensions - { - public static IUmbracoBuilder AddGoogleBackofficeAuthentication(this IUmbracoBuilder builder) - { - builder.AddBackOfficeExternalLogins(logins => - { - logins.AddBackOfficeLogin( - backOfficeAuthenticationBuilder => - { - backOfficeAuthenticationBuilder.AddGoogle( - // The scheme must be set with this method to work for the back office - backOfficeAuthenticationBuilder.SchemeForBackOffice(GoogleBackOfficeExternalLoginProviderOptions.SchemeName), - options => - { - // By default this is '/signin-google' but it needs to be changed to this - options.CallbackPath = "/umbraco-google-signin"; - options.ClientId = "YOURCLIENTID"; - options.ClientSecret = "YOURCLIENTSECRET"; - }); - }); - }); - return builder; - } - } -} -``` - -And another, but fairly similar, example of configuration for Google Authentication for members may look like: - -``` -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Web.UI.NetCore.Configuration -{ - public static class GoogleMemberAuthenticationExtensions - { - public static IUmbracoBuilder AddGoogleMemberAuthentication(this IUmbracoBuilder builder) - { - builder.AddMemberExternalLogins(logins => - { - logins.AddMemberLogin( - memberAuthenticationBuilder => - { - memberAuthenticationBuilder.AddGoogle( - // The scheme must be set with this method to work for the back office - memberAuthenticationBuilder.SchemeForMembers(GoogleMemberExternalLoginProviderOptions.SchemeName), - options => - { - options.ClientId = "YOURCLIENTID"; - options.ClientSecret = "YOURCLIENTSECRET"; - }); - }); - }); - return builder; - } - } -} -``` - -Finally, update `ConfigureServices` in your `Startup.cs` class to register your configuration with Umbraco. An example may look like: - -``` -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddGoogleBackofficeAuthentication() - .AddGoogleMemberAuthentication() - .Build(); -} -``` - -For a more in depth article on how to setup OAuth providers in .NET refer to the [Microsoft Documentation](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/?view=aspnetcore-5.0\&tabs=visual-studio). - -Depending on the provider you've configured and its caption/color, the end result will look similar to this for users: - -![OAuth Login Screen](images/google-oauth-v8.png) - -Because Umbraco do not control the UI of members, this can be setup to look exactly like you would like, but Umbraco ships with partial macro snippets for `Login` that will show all configured external login providers. - -## Auto-linking accounts for custom OAuth providers - -Traditionally a backoffice user or members will need to exist first and then that user can link their user account to an external login provider in the backoffice. In many cases however, the external login provider you install will be the source of truth for all of your users. - -In this case, you would want to be able to create user accounts in your external login provider and then have that user given access to the backoffice without having to create the user in the backoffice first. This is done via auto-linking. - -This could also be the case for members if your website allows public creation of members. In this case, the creation process can be simplified by allowing auto-linking the external account. E.g. using Facebook, Twitter or Google. - -Read more about [auto linking](auto-linking.md). diff --git a/10/umbraco-cms/reference/security/images/AD_Login (1) (1).png b/10/umbraco-cms/reference/security/images/AD_Login (1) (1).png deleted file mode 100644 index 5c1f2856931..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/AD_Login (1).png b/10/umbraco-cms/reference/security/images/AD_Login (1).png deleted file mode 100644 index 5c1f2856931..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login (1).png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/AD_Login.png b/10/umbraco-cms/reference/security/images/AD_Login.png deleted file mode 100644 index 5c1f2856931..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/AD_Login_Members (1) (1).png b/10/umbraco-cms/reference/security/images/AD_Login_Members (1) (1).png deleted file mode 100644 index cca354a8a01..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login_Members (1) (1).png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/AD_Login_Members (1) (2).png b/10/umbraco-cms/reference/security/images/AD_Login_Members (1) (2).png deleted file mode 100644 index cca354a8a01..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login_Members (1) (2).png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/AD_Login_Members (1).png b/10/umbraco-cms/reference/security/images/AD_Login_Members (1).png deleted file mode 100644 index cca354a8a01..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login_Members (1).png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/AD_Login_Members.png b/10/umbraco-cms/reference/security/images/AD_Login_Members.png deleted file mode 100644 index cca354a8a01..00000000000 Binary files a/10/umbraco-cms/reference/security/images/AD_Login_Members.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/configure-2fa.png b/10/umbraco-cms/reference/security/images/configure-2fa.png deleted file mode 100644 index 5fc88c3c1b0..00000000000 Binary files a/10/umbraco-cms/reference/security/images/configure-2fa.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/disable-2fa.png b/10/umbraco-cms/reference/security/images/disable-2fa.png deleted file mode 100644 index 2904b0b8246..00000000000 Binary files a/10/umbraco-cms/reference/security/images/disable-2fa.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/enable-2fa.png b/10/umbraco-cms/reference/security/images/enable-2fa.png deleted file mode 100644 index 4220995555e..00000000000 Binary files a/10/umbraco-cms/reference/security/images/enable-2fa.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/export-member.png b/10/umbraco-cms/reference/security/images/export-member.png deleted file mode 100644 index 61902aa08b7..00000000000 Binary files a/10/umbraco-cms/reference/security/images/export-member.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/foldersondisk-after.png b/10/umbraco-cms/reference/security/images/foldersondisk-after.png deleted file mode 100644 index e32b7348c89..00000000000 Binary files a/10/umbraco-cms/reference/security/images/foldersondisk-after.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/foldersondisk-before.png b/10/umbraco-cms/reference/security/images/foldersondisk-before.png deleted file mode 100644 index 165a58a08bb..00000000000 Binary files a/10/umbraco-cms/reference/security/images/foldersondisk-before.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/google-oauth-v8.png b/10/umbraco-cms/reference/security/images/google-oauth-v8.png deleted file mode 100644 index 0fd07e6dcac..00000000000 Binary files a/10/umbraco-cms/reference/security/images/google-oauth-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/login-2fa.png b/10/umbraco-cms/reference/security/images/login-2fa.png deleted file mode 100644 index d4d0dbfefaf..00000000000 Binary files a/10/umbraco-cms/reference/security/images/login-2fa.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/sensitive-data-hidden-v8.png b/10/umbraco-cms/reference/security/images/sensitive-data-hidden-v8.png deleted file mode 100644 index b0264767ced..00000000000 Binary files a/10/umbraco-cms/reference/security/images/sensitive-data-hidden-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/sensitive-data-hidden.png b/10/umbraco-cms/reference/security/images/sensitive-data-hidden.png deleted file mode 100644 index e393e07508d..00000000000 Binary files a/10/umbraco-cms/reference/security/images/sensitive-data-hidden.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/sensitive-data-user-group-v8.png b/10/umbraco-cms/reference/security/images/sensitive-data-user-group-v8.png deleted file mode 100644 index 392cf74e23a..00000000000 Binary files a/10/umbraco-cms/reference/security/images/sensitive-data-user-group-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/sensitive-data-user-group.jpg b/10/umbraco-cms/reference/security/images/sensitive-data-user-group.jpg deleted file mode 100644 index 32e769a51f0..00000000000 Binary files a/10/umbraco-cms/reference/security/images/sensitive-data-user-group.jpg and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/update-member-type-v8.png b/10/umbraco-cms/reference/security/images/update-member-type-v8.png deleted file mode 100644 index 8ffd02dbaf5..00000000000 Binary files a/10/umbraco-cms/reference/security/images/update-member-type-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/update-member-type.png b/10/umbraco-cms/reference/security/images/update-member-type.png deleted file mode 100644 index 88d13424bde..00000000000 Binary files a/10/umbraco-cms/reference/security/images/update-member-type.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/user-panel.png b/10/umbraco-cms/reference/security/images/user-panel.png deleted file mode 100644 index 4ed3da40178..00000000000 Binary files a/10/umbraco-cms/reference/security/images/user-panel.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/verify-disable.png b/10/umbraco-cms/reference/security/images/verify-disable.png deleted file mode 100644 index 544fe6e4e06..00000000000 Binary files a/10/umbraco-cms/reference/security/images/verify-disable.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/webconfig-after.png b/10/umbraco-cms/reference/security/images/webconfig-after.png deleted file mode 100644 index cf2af909570..00000000000 Binary files a/10/umbraco-cms/reference/security/images/webconfig-after.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/images/webconfig-before.png b/10/umbraco-cms/reference/security/images/webconfig-before.png deleted file mode 100644 index c350ea7fcc8..00000000000 Binary files a/10/umbraco-cms/reference/security/images/webconfig-before.png and /dev/null differ diff --git a/10/umbraco-cms/reference/security/password-reset.md b/10/umbraco-cms/reference/security/password-reset.md deleted file mode 100644 index e711c7da4bb..00000000000 --- a/10/umbraco-cms/reference/security/password-reset.md +++ /dev/null @@ -1,26 +0,0 @@ ---- - - ---- - -# Password reset - -It's impossible to brute force the authentication on the login screen because after `MaxFailedAccessAttemptsBeforeLockout` the account of the user will be locked, and until that account is unlocked in the Users section, no attempt will succeed. - -## Password reset on login screen - -When you submit the password reset form, an email is sent to the user with a link. This link contains a random token for this user that is valid for 24 hours. - -The settings `AllowPasswordReset` is documented in the [Umbraco Security Settings](../configuration/securitysettings.md) and e-mail configuration settings in [Backoffice Login Password Reset Section](../../fundamentals/backoffice/login.md#password-reset) - -## Password reset of a non-existing user - -If the user that is specified in the form does not exist, no e-mail will be sent and there will be no response in the form that this user does not exist. This is done to prevent leaking which users have an account. - -## Password reset of a locked user - -If a user is locked out, it is possible to do a password reset. After the e-mail with the password reset link is followed, the user will still be locked out unless the user has specified the new password, in which case the user will automatically be unlocked. - -## Reset admin user password - -If you lost the admin user password and you need to reset it, [check this article](reset-admin-password.md). diff --git a/10/umbraco-cms/reference/security/reset-admin-password.md b/10/umbraco-cms/reference/security/reset-admin-password.md deleted file mode 100644 index 619747b0c73..00000000000 --- a/10/umbraco-cms/reference/security/reset-admin-password.md +++ /dev/null @@ -1,31 +0,0 @@ -# Reset admin password - -There is one default admin user in any Umbraco installation. This is the first user of the system. - -## Step one: Clear the connection string status in configuration - -The first step is to clear the connection string to the database in the configuration. This is done to trigger the installation wizard. - -That means that in your appsettings configuration files it should look like this: - -```json -{ - "ConnectionStrings": { - "umbracoDbDSN": "" - } -} -``` - -{% hint style="warning" %} -**Note that configuration can be read from many sources** - -Remember to check this connection string is not provided through environment variables or other configuration sources. -{% endhint %} - -## Step Two: Run the installer - -If you now open your browser and surf to the website, you will see that the installer launches. Enter your new details, and use the original connection string. You are good to go. - -{% hint style="warning" %} -Make sure you protect a production websites from being highjacked as anyone will be able to reset the password during the last step. This does also work if your site is in an upgrading state. -{% endhint %} diff --git a/10/umbraco-cms/reference/security/security-hardening.md b/10/umbraco-cms/reference/security/security-hardening.md deleted file mode 100644 index 47c502d7a0e..00000000000 --- a/10/umbraco-cms/reference/security/security-hardening.md +++ /dev/null @@ -1,53 +0,0 @@ ---- - ---- - -# Umbraco Security Hardening - -Here you find some tips and trick for hardening the security of your Umbraco installation. - -## Lock down access to your Umbraco folder (IIS) - -It’s considered a good practice to lock down the Umbraco folder to specific IP addresses and/or IP ranges to ensure this folder is not available to everyone. - -The prerequisite of this to work is that you’re using [IISRewrite](../routing/iisrewriterules.md) - -If you’ve made sure that you’ve installed this on your server we can start locking down our Umbraco folder. This can be down by following these three steps. - -1. We are going to lock down /Umbraco/, but because API-controllers and Surface-controller will use the path /umbraco/api/ and /umbraco/surface/ these will also be locked down. Our first rule in the IISRewrite.config will be used to make sure that these are not locked by IP-address. - -```xml - - - - -``` - -Some older versions of Umbraco also relied on /umbraco/webservices/ for loadbalancing purposes. If you're loadbalancing you should also add umbraco/webservices to the rule. - -```xml - - - - -``` - -2. Get the IP-addresses of your client and write these down like a regular expression. If the IP-addresses are for example 213.3.10.8 and 88.4.43.108 the regular expression would be "213.3.10.8|88.4.43.108". - -3. Lock down the Umbraco folder by putting this rule into your IISRewrite-rules - -```xml - - - - - - - -``` - -{% hint style="info" %} -If your server is behind a load balancer, you should use `{HTTP_X_FORWARDED_FOR}` instead of `{REMOTE_ADDR}` as the input for the rule. -{% endhint %} - -If you now go to `/umbraco/` from a different IP-address the login screen will not be rendered. diff --git a/10/umbraco-cms/reference/security/security-settings.md b/10/umbraco-cms/reference/security/security-settings.md deleted file mode 100644 index 1ae58f8f0c0..00000000000 --- a/10/umbraco-cms/reference/security/security-settings.md +++ /dev/null @@ -1,27 +0,0 @@ ---- - - ---- - -# Umbraco Security Settings - -## Password settings - -The settings for Umbraco passwords are configurable in appsettings. There are two different configuration objects - One for Umbraco Members and one for Users. - -For more information see the [Security Settings documentation](../configuration/securitysettings.md#user-password-settings). - -## Password reset settings - -Umbraco backend users can [reset their own password](password-reset.md), or if they try too much, have a locked out account. - -To deactivate the User password reset look at the [Umbraco Settings Security](../configuration/securitysettings.md#allow-password-reset) section. - -To configure password reset verify the [Backoffice Login Password Reset](../../fundamentals/backoffice/login.md#password-reset) section. - -## Other security settings - -* [The Umbraco timeout in minutes](../configuration/globalsettings.md#timeout) -* [disableAlternativeTemplates](../configuration/webroutingsettings.md#disable-alternative-templates) If set to false this can be used to try to render pages in a way that they are not supposed to -* [disableFindContentByIdPath](../configuration/webroutingsettings.md#disable-find-content-by-id-path) If set to false this can be used to do an enumeration of the nodes in your website and find hidden pages. -* Umbraco Forms: [AntiForgeryToken](https://docs.umbraco.com/umbraco-forms/developer/configuration#enableantiforgerytoken) and DisableFormCaching diff --git a/10/umbraco-cms/reference/security/sensitive-data-on-members.md b/10/umbraco-cms/reference/security/sensitive-data-on-members.md deleted file mode 100644 index 3938eca352d..00000000000 --- a/10/umbraco-cms/reference/security/sensitive-data-on-members.md +++ /dev/null @@ -1,52 +0,0 @@ -# Sensitive data - -Marking fields and properties on member data as sensitive will hide the data in those fields for backoffice users that are not privy to the data. - -In this article, you will get an overview of how you can grant and/or deny your users access to sensitive data as well as how to mark data as sensitive. - -## Grant or deny access to sensitive data - -Every new Umbraco installation ships with a default set of User Groups. One of them is the **Sensitive data User Group**. To give users in the backoffice access to view and work with sensitive data, they need to be part of the Sensitive data User Group. - -Any users who are not part of the Sensitive data User Group, will not be able to see the data in the properties that are marked as sensitive. Instead, they will see a generic message: "_This value is hidden. If you need access to view this value please contact your website administrator._" - -![Sensitive data hidden](images/sensitive-data-hidden-v8.png) - -While not part of the Sensitive data User Group it is also not possible to export members or member data. - -Follow these steps in order to grant a user access to sensitive data: - -* Navigate to the **Users** section in the Umbraco backoffice. -* Ensure that **Users** is selected from the Users tree. -* Select the **Groups** menu in the top-right corner. -* Choose the **Sensitive data** group. - -![Sensitive data user group](images/sensitive-data-user-group-v8.png) - -* Click **Add** in the **Users** box on the right. -* Select the users you want to give access to the sensitive data. -* Click **Submit**. -* **Save** the User Group. - -The users you have added to the Sensitive data User Group will now be able to: - -* See member data that has been marked as sensitive, -* Mark data and properties on Member Types as sensitive, and -* Export members and member data. - -## Marking data as sensitive - -Once your user is added to the Sensitive data User Group, you have access to add and configure member properties containing sensitive data. - -* Navigate to the **Settings** section in the Umbraco backoffice. -* Open the **Member Types** in the **Settings** tree. -* Select the Member Type you wish to edit. -* **Add** a property or configure an existing property. -* Locate the **Is sensitive data** option at the bottom of the **Property settings** dialog. -* Click to enable. -* Click **Submit** to update the property configuration. -* Click **Save** to save the changes on the Member Type. - -When the **Is sensitive data** option is enabled, the value and data in the property will only be visible to the users with access to sensitive data. - -![Update member type](images/update-member-type-v8.png) diff --git a/10/umbraco-cms/reference/security/serverside-file-validation.md b/10/umbraco-cms/reference/security/serverside-file-validation.md deleted file mode 100644 index 2da7702e2a8..00000000000 --- a/10/umbraco-cms/reference/security/serverside-file-validation.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -meta.Title: Server-side File Validation -description: This section describes how you can implement File Validation ---- - -# Server-side file validation - -Sometimes it might be necessary to validate the contents of a file before it gets saved to disk when uploading trough the backoffice. - -To help with this, Umbraco supplies a `FileStreamSecurityValidator` that runs all registered `IFileStreamSecurityAnalyzer` implementations on the file streams it receives from it's different file upload endpoints. When any of the analyzers deem the file to be unsafe, the endpoint disregards the file and shows a relevant validation message where appropriate. This all happens in memory before the stream is written to a temporary file location. - -### Implementing a FileStreamSecurityValidator - -The `IFileStreamSecurityAnalyzer` needs a single method to be implemented: - -* `IsConsideredSafe`: This method should return false if the analyzer finds a reason not to trust the file - -### Example FileStreamSecurityAnalyzer - -The following class shows how one could potentially guard against Cross-site scripting(XSS) vulnerabilities in an svg file. - -```csharp -public class SvgXssSecurityAnalyzer : IFileStreamSecurityAnalyzer - { - public bool ShouldHandle(Stream fileStream) - { - // reduce memory footprint by partially reading the file - var startBuffer = new byte[256]; - var endBuffer = new byte[256]; - fileStream.Read(startBuffer); - if (endBuffer.Length > fileStream.Length) - fileStream.Seek(0, SeekOrigin.Begin); - else - fileStream.Seek(fileStream.Length - endBuffer.Length, SeekOrigin.Begin); - fileStream.Read(endBuffer); - var startString = System.Text.Encoding.UTF8.GetString(startBuffer); - var endString = System.Text.Encoding.UTF8.GetString(endBuffer); - return startString.Contains(""); - } - - public bool IsConsideredSafe(Stream fileStream) - { - var streamReader = new StreamReader(fileStream); // do not use a using as this will dispose of the underlying stream - var fileContent = streamReader.ReadToEnd(); - return !(fileContent.Contains("")); - } - } -``` - -You can [register it during startup or with a composer](https://docs.umbraco.com/umbraco-cms/reference/using-ioc#registering-dependencies). - -This is an example of registering the class with a composer: - -```csharp -public class ServerSideValidationComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddSingleton(); - } - } -``` - -Then you can upload a file with the following content to the backoffice and see that it is not persisted. - -```xml - - - - - - - -``` diff --git a/10/umbraco-cms/reference/security/serverside-sanitizing.md b/10/umbraco-cms/reference/security/serverside-sanitizing.md deleted file mode 100644 index fdae363b317..00000000000 --- a/10/umbraco-cms/reference/security/serverside-sanitizing.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -versionFrom: 9.3.0 -meta.Title: Serverside Sanitizing -description: This section describes how to sanitize the Rich Text Editor serverside ---- - -# Sanitizing the Rich Text Editor - -The rich text editor is sanitized on the frontend by default, however, you may want to do this serverside as well. The libraries that are out there tend to have very strict, and therefore, problematic dependencies, so we'll leave it up to you how you want to sanitize the HTML. - -## Implementing your own IHtmlSanitizer - -To make this task as easy as possible we've added an abstraction called `IHtmlSanitizer`, by default this doesn't do anything, but you can overwrite it with your own implementation to handle sanitization how you see fit. This interface only has a single method `string Sanitize(string html)`, the output of this method is what will be stored in the database when you save a RichText editor. - -To add your own sanitizer you must first create a class the implements the interface: - -```c# -using Umbraco.Cms.Core.Security; - -namespace MySite.HtmlSanitization -{ - public class MyHtmlSanitizer : IHtmlSanitizer - { - public string Sanitize(string html) - { - // Sanitize the html parameter here - return "

Sanitized HTML

"; - } - } -} -``` - -As you can see this specific implementation doesn't do a whole lot, but the `Sanitize` method is where you can use a library, or even your own sanitizer implementation, to sanitize the RichText editor input. - -Now that you've added your own custom `IHtmlSanitizer` you must register it in the container to replace the existing NoOp sanitizer. - -You can register it directly in the `Startup.cs`, for instance using an extension method on the `IUmbracoBuilder`: - -Extension method: - -```c# -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Security; -using Umbraco.Extensions; - -namespace MySite.HtmlSanitization -{ - public static class BuilderExtensions - { - public static IUmbracoBuilder AddHtmlSanitizer(this IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - return builder; - } - } -} -``` - -Calling the extension method: - -```c# - public void ConfigureServices(IServiceCollection services) - { -#pragma warning disable IDE0022 // Use expression body for methods - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - .AddHtmlSanitizer() // Call you extension method here. - .Build(); -#pragma warning restore IDE0022 // Use expression body for methods - } -``` - -Or you can use a Composer: - -```c# -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Security; -using Umbraco.Extensions; - -namespace MySite.HtmlSanitization -{ - public class SanitizerComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - } - } -} -``` - -If you've followed along you'll now see that no matter what you type in a Rich Text Editor, when you save it, it'll always only contain a heading that says "Sanitized HTML", this is of course isn't that helpful, but it shows that everything is working as expected, and that whatever your sanitizer returns is what will be saved. diff --git a/10/umbraco-cms/reference/security/setup-umbraco-for-a-fips-server.md b/10/umbraco-cms/reference/security/setup-umbraco-for-a-fips-server.md deleted file mode 100644 index 2d3846c4ae4..00000000000 --- a/10/umbraco-cms/reference/security/setup-umbraco-for-a-fips-server.md +++ /dev/null @@ -1,40 +0,0 @@ ---- - - ---- - -# Setup Umbraco for a FIPS Compliant Server - -_This tutorial walks through configuring Umbraco and Lucene to be FIPS compliant and serve up websites on a server with FIPS enabled._ - -{% hint style="warning" %} -FIPS should only be added for compliance. It is **not** a recommended approach for added security. For more information read [Why Microsoft is not recommending "FIPS Mode" anymore.](https://techcommunity.microsoft.com/t5/microsoft-security-baselines/why-we-8217-re-not-recommending-8220-fips-mode-8221-anymore/ba-p/701037) -{% endhint %} - -## What is FIPS? - -The Federal Information Processing Standard (FIPS) Publication 140-2, ([FIPS PUB 140-2][1]), is a U.S. government computer security standard used to define approved cryptographic modules. The FIPS 140 standard also sets forth requirements for key generation and for key management. - -Microsoft Windows has a "FIPS mode" of operation where it detects the cryptographic algorithms used by software running on it and will throw exceptions if it detects the use of non-FIPS compliant algorithms. Using MD5 hashing is generally the biggest culprit of issues running on FIPS enabled servers. - -## How can I test my site with FIPS enabled? - -FIPS can be enabled through your Local Group Policy, Registry Setting, or Network Adapter setting. For more information about how to enable FIPS mode on Windows see this tutorial: [How-to Enable FIPS on Windows][2] - -## What version of Umbraco is FIPS compliant? - -Umbraco 7.6.4+ has implemented checks for when FIPS mode is enabled on the server that it is installed on. When FIPS mode is detected, the cryptographic algorithms for hashing are changed to a FIPS compliant algorithm. When FIPS mode is disabled, then Umbraco uses backward compatible algorithms (MD5) so as not to affect existing installs. As of Umbraco version 7.6.4, the FIPS compliant cryptographic algorithm used is SHA1. - -## Umbraco 9.0.0 and key dependencies are FIPS compliant - -Since Umbraco 9, the dependency to Lucene.NET is updated to version 4+. Thereby are both Umbraco and all key dependencies FIPS compliant. - -## FAQ - -__Can I install Umbraco directly on a version of Windows with FIPS mode enabled?__ - -Installing to the FIPS server may not work. It's best to deploy an existing known working version to the FIPS server. - -[1]:https://csrc.nist.gov/publications/PubsFIPS.html#140-2 -[2]:https://www.howtogeek.com/245859/why-you-shouldnt-enable-fips-compliant-encryption-on-windows/ -[3]:../../fundamentals/setup/upgrading/ diff --git a/10/umbraco-cms/reference/security/ssl-https.md b/10/umbraco-cms/reference/security/ssl-https.md deleted file mode 100644 index dc18d8f2de7..00000000000 --- a/10/umbraco-cms/reference/security/ssl-https.md +++ /dev/null @@ -1,105 +0,0 @@ ---- - - -meta.Title: Learn how to enforce the use of HTTPS (UseHttps) on your Umbraco websites. -description: >- - In production environments it is highly recommend that you enforce the use of - HTTPS (UseHttps). It grealy increases the general trust of your site and - guards you against various attacks, like 'Man in ---- - -# HTTPS - -We highly encourage the use of HTTPS on Umbraco websites especially in production environments. By using HTTPS you greatly improve the security of your website. - -There are several benefits of HTTPS: - -* Trust - when your site is delivered over HTTPS your users will see that your site is secured, they are able to view the certificate assigned to your site and know that your site is legitimate -* Removing an attack vector called ["Man in the middle"](https://owasp.org/www-community/attacks/Manipulator-in-the-middle\_attack) (or network Sniffing) -* Guards against [Phishing](https://en.wikipedia.org/wiki/Phishing), an attacker will have a hard time obtaining an authentic SSL certificate -* Google likes HTTPS, it may help your site's rankings - -Another benefits of HTTPS is that you are able to use the [http2](https://en.wikipedia.org/wiki/HTTP/2) protocol if your web server and browser support it. - -## Set UseHttps configuration option - -Umbraco allows you to force HTTPS for all backoffice communications by using the following configuration: - -In Umbraco 9, set the UseHttps key in `appSettings` to true. - -```json -{ - "Umbraco": { - "CMS": { - "Global": { - "UseHttps": true - } - } - } -} -``` - -This options does several things when it is turned on: - -* Ensures that the backoffice authentication cookie is set to [secure only](https://owasp.org/www-community/controls/SecureCookieAttribute) (so it can only be transmitted over https) -* All non-https requests to any backoffice controller is redirected to https -* All self delivered Umbraco requests (i.e. scheduled publishing, keep alive, etc...) are performed over https -* All Umbraco notification emails with links generated have https links -* All authorization attempts for backoffice handlers and services will be denied if the request is not over https - -## Redirect traffic in code - -The .NET5+ way to handle this, is by adding this `HttpsRedirectionMiddleware` to your pipeline in `Startup.cs`. This can be done by adding `app.UseHttpsRedirection();` before the call to `app.UseUmbraco()` in the `Configure` method: - -```cs -public class Startup -{ - ... - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - ... - app.UseHttpsRedirection(); - - app.UseUmbraco() - .WithMiddleware(u => - { - u.UseBackOffice(); - u.UseWebsite(); - }) - .WithEndpoints(u => - { - u.UseInstallerEndpoints(); - u.UseBackOfficeEndpoints(); - u.UseWebsiteEndpoints(); - }); - } -} -``` - -## Redirect traffic on IIS - -Once you enable HTTPS for your site you should redirect all requests to your site to HTTPS, this can be done with an IIS rewrite rule. The IIS rewrite module needs to be installed for this to work, most hosting providers will have that enabled by default. - -In your `web.config` find or add the `` section and put the following rule in there. This rule will redirect all requests for the site http://mysite.com URL to the secure https://mysite.com URL and respond with a permanent redirect status. - -```xml - - - - - - - - -``` - -{% hint style="info" %} -The rule includes an ignore for `localhost`. If you run your local environment on a different URL than `localhost` you can add additional ignore rules. Additionally, if you have a staging environment that doesn't run on HTTPS, you can add that to the ignore rules too. -{% endhint %} - -## SSL versus TLS - -_In HTTPS, the communication protocol is encrypted using Transport Layer Security (TLS), or, formerly, its predecessor, Secure Sockets Layer (SSL)_ - [wikipedia](https://en.wikipedia.org/wiki/HTTPS) - -While the deprecated SSL (2.0 and 3.0) are not supported anymore by modern browsers, some of the Umbraco configuration still uses SSL. But rest assured, that is **only** the name. diff --git a/10/umbraco-cms/reference/security/two-factor-authentication.md b/10/umbraco-cms/reference/security/two-factor-authentication.md deleted file mode 100644 index d409379f0e1..00000000000 --- a/10/umbraco-cms/reference/security/two-factor-authentication.md +++ /dev/null @@ -1,595 +0,0 @@ ---- -description: >- - Umbraco users and members support a two-factor authentication (2FA) - abstraction for implementing a 2FA provider of your choice ---- - -# Two-factor Authentication - -Two-factor authentication (2FA) for Umbraco members is activated by implementing an `ITwoFactorProvider` interface and registering the implementation. The implementation can use third-party packages to archive for example support for authentication apps like Microsoft- or Google Authentication App. - -{% hint style="info" %} - -If you are using [Umbraco Cloud](https://umbraco.com/products/umbraco-cloud/), you can enable multi-factor authentication in Umbraco ID. For more information, see the [Multi-Factor Authentication](https://docs.umbraco.com/umbraco-cloud/set-up/multi-factor-authentication-on-cloud) article. - -{% endhint %} - -## Two-factor authentication for Members - -Since Umbraco does not control how the UI is for member login and profile edit, the UI for 2FA is shipped as part of the snippets for macros. These can be used as a starting point, before styling the page as you would like. - -### Example implementation for Authenticator Apps for Members - -In the following example, we will use the [GoogleAuthenticator NuGet Package](https://www.nuget.org/packages/GoogleAuthenticator/). Despite the name, this package works for both Google and Microsoft authenticator apps and can be used to generate the QR code needed to activate the app for the website. - -``` -using System; -using System.Threading.Tasks; -using Google.Authenticator; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; - -namespace My.Website -{ - /// - /// Model with the required data to setup the authentication app. - /// - public class QrCodeSetupData - { - /// - /// The secret unique code for the user and this ITwoFactorProvider. - /// - public string Secret { get; init; } - - /// - /// The SetupCode from the GoogleAuthenticator code. - /// - public SetupCode SetupCode { get; init; } - } - - /// - /// App Authenticator implementation of the ITwoFactorProvider - /// - public class UmbracoAppAuthenticator : ITwoFactorProvider - { - /// - /// The unique name of the ITwoFactorProvider. This is saved in a constant for reusability. - /// - public const string Name = "UmbracoAppAuthenticator"; - - private readonly IMemberService _memberService; - - /// - /// Initializes a new instance of the class. - /// - public UmbracoAppAuthenticator(IMemberService memberService) - { - _memberService = memberService; - } - - /// - /// The unique provider name of ITwoFactorProvider implementation. - /// - /// - /// This value will be saved in the database to connect the member with this ITwoFactorProvider. - /// - public string ProviderName => Name; - - /// - /// Returns the required data to setup this specific ITwoFactorProvider implementation. In this case it will contain the url to the QR-Code and the secret. - /// - /// The key of the user or member - /// The secret that ensures only this user can connect to the authenticator app - /// The required data to setup the authenticator app - public Task GetSetupDataAsync(Guid userOrMemberKey, string secret) - { - var member = _memberService.GetByKey(userOrMemberKey); - - var twoFactorAuthenticator = new TwoFactorAuthenticator(); - SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode("My application name", member.Username, secret, false); - return Task.FromResult(new QrCodeSetupData() - { - SetupCode = setupInfo, - Secret = secret - }); - } - - /// - /// Validated the code and the secret of the user. - /// - public bool ValidateTwoFactorPIN(string secret, string code) - { - var twoFactorAuthenticator = new TwoFactorAuthenticator(); - return twoFactorAuthenticator.ValidateTwoFactorPIN(secret, code); - } - - /// - /// Validated the two factor setup - /// - /// Called to confirm the setup of two factor on the user. In this case we confirm in the same way as we login by validating the PIN. - public bool ValidateTwoFactorSetup(string secret, string token) => ValidateTwoFactorPIN(secret, token); - } -} -``` - -First, we create a model with the information required to set up the 2FA provider and then we implement the `ITwoFactorProvider` with the use of the `TwoFactorAuthenticator` from the GoogleAuthenticator NuGet package. - -Now we need to register the `UmbracoAppAuthenticator` implementation. This can be done on the `IUmbracoBuilder` in your startup or a composer. - -``` -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Security; -using Umbraco.Extensions; - -namespace My.Website -{ - public class UmbracoAppAuthenticatorComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - var identityBuilder = new MemberIdentityBuilder(builder.Services); - identityBuilder.AddTwoFactorProvider(UmbracoAppAuthenticator.Name); - } - } -} -``` - -At this point, the 2FA is active, but no members have set up 2FA yet. The setup of 2FA depends on the type. In the case of App Authenticator, we will add the following to our view showing the edit profile of the member. - -``` -@using Umbraco.Cms.Core.Services -@using Umbraco.Cms.Web.Website.Controllers -@using Umbraco.Cms.Web.Website.Models -@using My.Website @* Or whatever your namespace with the QrCodeSetupData model is *@ -@inject MemberModelBuilderFactory memberModelBuilderFactory -@inject ITwoFactorLoginService twoFactorLoginService -@{ - // Build a profile model to edit - var profileModel = await memberModelBuilderFactory - .CreateProfileModel() - .BuildForCurrentMemberAsync(); - - // Show all two factor providers - var providerNames = twoFactorLoginService.GetAllProviderNames(); - if (providerNames.Any()) - { -
- foreach (var providerName in providerNames) - { - var setupData = await twoFactorLoginService.GetSetupInfoAsync(profileModel.Key, providerName); - if (setupData is null) - { - @using (Html.BeginUmbracoForm(nameof(UmbTwoFactorLoginController.Disable))) - { - - - } - } - else if(setupData is QrCodeSetupData qrCodeSetupData) - { - @using (Html.BeginUmbracoForm(nameof(UmbTwoFactorLoginController.ValidateAndSaveSetup))) - { -

Setup @providerName

- -

Scan the code above with your authenticator app
and enter the resulting code here to validate:

- - - - - } - } - } - } -} -``` - -In this razor-code sample, we get the current member's unique key and list all registered `ITwoFactorProvider` implementations. - -If the `setupData` is `null` for the specified `providerName` it means the provider is already set up. In this case, we show a disable button. Otherwise, we check the type and show the UI for how to set up the App Authenticator, by showing the QR Code and an input field to validate the code from the App Authenticator. - -The last part required is to use the `Login` Partial Macro snippet. - -### Notification when 2FA is requested for a member - -When a 2FA login is requested for a member, the `MemberTwoFactorRequestedNotification` is published. This notification can also be used to send the member a one-time password via e-mail or phone. Even though these 2FA types are [not considered secure](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/mfa?view=aspnetcore-6.0#mfa-sms) as App Authentication, it is still a massive improvement compared to no 2FA. - -## Two-factor authentication for Users - -Umbraco controls how the UI is for user login and user edits, but will still need a view for configuring each 2FA provider. - -### Example implementation for Authenticator Apps for Users - -In the following example, we will use the [GoogleAuthenticator NuGet Package](https://www.nuget.org/packages/GoogleAuthenticator/). Despite the name, this package works for both Google and Microsoft authenticator apps and can be used to generate the QR code needed to activate the app for the website. - -{% tabs %} -{% tab title="Latest version" %} - -``` -using System.Runtime.Serialization; -using Google.Authenticator; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace My.Website -{ - [DataContract] - public class TwoFactorAuthInfo - { - [DataMember(Name = "qrCodeSetupImageUrl")] - public string? QrCodeSetupImageUrl { get; set; } - - [DataMember(Name = "secret")] - public string? Secret { get; set; } - } - - /// - /// App Authenticator implementation of the ITwoFactorProvider - /// - public class UmbracoUserAppAuthenticator : ITwoFactorProvider - { - private readonly IUserService _userService; - - /// - /// The unique name of the ITwoFactorProvider. This is saved in a constant for reusability. - /// - public const string Name = "UmbracoUserAppAuthenticator"; - - /// - /// Initializes a new instance of the class. - /// - public UmbracoUserAppAuthenticator(IUserService userService) - { - _userService = userService; - - } - - /// - /// The unique provider name of ITwoFactorProvider implementation. - /// - /// - /// This value will be saved in the database to connect the member with this ITwoFactorProvider. - /// - public string ProviderName => Name; - - /// - /// Returns the required data to setup this specific ITwoFactorProvider implementation. In this case it will contain the url to the QR-Code and the secret. - /// - /// The key of the user or member - /// The secret that ensures only this user can connect to the authenticator app - /// The required data to setup the authenticator app - public Task GetSetupDataAsync(Guid userOrMemberKey, string secret) - { - var user = _userService.GetByKey(userOrMemberKey); - - var twoFactorAuthenticator = new TwoFactorAuthenticator(); - SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode("My application name", user.Username, secret, false); - return Task.FromResult(new TwoFactorAuthInfo() - { - QrCodeSetupImageUrl = setupInfo.QrCodeSetupImageUrl, - Secret = secret - }); - } - - /// - /// Validated the code and the secret of the user. - /// - public bool ValidateTwoFactorPIN(string secret, string code) - { - var twoFactorAuthenticator = new TwoFactorAuthenticator(); - return twoFactorAuthenticator.ValidateTwoFactorPIN(secret, code); - } - - /// - /// Validated the two factor setup - /// - /// Called to confirm the setup of two factor on the user. In this case we confirm in the same way as we login by validating the PIN. - public bool ValidateTwoFactorSetup(string secret, string token) => ValidateTwoFactorPIN(secret, token); - } -} -``` - -{% endtab %} - -{% tab title="Umbraco 9" %} - -``` -using System; -using System.Runtime.Serialization; -using System.Threading.Tasks; -using Google.Authenticator; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace My.Website -{ - [DataContract] - public class TwoFactorAuthInfo - { - [DataMember(Name = "qrCodeSetupImageUrl")] - public string QrCodeSetupImageUrl { get; set; } - - [DataMember(Name = "secret")] - public string Secret { get; set; } - } - - /// - /// App Authenticator implementation of the ITwoFactorProvider - /// - public class UmbracoUserAppAuthenticator : ITwoFactorProvider - { - private readonly IUserService _userService; - - /// - /// The unique name of the ITwoFactorProvider. This is saved in a constant for reusability. - /// - public const string Name = "UmbracoUserAppAuthenticator"; - - /// - /// Initializes a new instance of the class. - /// - public UmbracoUserAppAuthenticator(IUserService userService) - { - _userService = userService; - - } - - /// - /// The unique provider name of ITwoFactorProvider implementation. - /// - /// - /// This value will be saved in the database to connect the member with this ITwoFactorProvider. - /// - public string ProviderName => Name; - - /// - /// Returns the required data to setup this specific ITwoFactorProvider implementation. In this case it will contain the url to the QR-Code and the secret. - /// - /// The key of the user or member - /// The secret that ensures only this user can connect to the authenticator app - /// The required data to setup the authenticator app - public Task GetSetupDataAsync(Guid userOrMemberKey, string secret) - { - var user = _userService.GetByKey(userOrMemberKey); - - var twoFactorAuthenticator = new TwoFactorAuthenticator(); - SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode("My application name", user.Username, secret, false); - return Task.FromResult(new TwoFactorAuthInfo() - { - QrCodeSetupImageUrl = setupInfo.QrCodeSetupImageUrl, - Secret = secret - }); - } - - /// - /// Validated the code and the secret of the user. - /// - public bool ValidateTwoFactorPIN(string secret, string code) - { - var twoFactorAuthenticator = new TwoFactorAuthenticator(); - return twoFactorAuthenticator.ValidateTwoFactorPIN(secret, code); - } - - /// - /// Validated the two factor setup - /// - /// Called to confirm the setup of two factor on the user. In this case we confirm in the same way as we login by validating the PIN. - public bool ValidateTwoFactorSetup(string secret, string token) => ValidateTwoFactorPIN(secret, token); - } -} -``` - -{% endtab %} -{% endtabs %} - -First, we create a model with the information required to set up the 2FA provider and then we implement the `ITwoFactorProvider` with the use of the `TwoFactorAuthenticator` from the GoogleAuthenticator NuGet package. - -Now we need to register the `UmbracoUserAppAuthenticator` implementation and the view to show to set up this provider. This can be done on the `IUmbracoBuilder` in your startup or a composer. - -``` -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Web.BackOffice.Security; -using Umbraco.Extensions; - -namespace My.Website -{ - public class UmbracoAppAuthenticatorComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - var identityBuilder = new BackOfficeIdentityBuilder(builder.Services); - - identityBuilder.AddTwoFactorProvider(UmbracoUserAppAuthenticator.Name); - - builder.Services.Configure(UmbracoUserAppAuthenticator.Name, options => - { - options.SetupViewPath = "..\\App_Plugins\\TwoFactorProviders\\twoFactorProviderGoogleAuthenticator.html"; - }); - } - } -} -``` - -Now we need to create the view we just configured, in the path we choose. - -```html -
- - - -
- - - - - - - - - - - - -
- QR code for Google Authenticator -
- - - - - -
- - Invalid code entered - -
- -
- -
- -
- -
- - - - - - - - - - - - - - - -
- -
- -
-``` - -As this view uses an angular controller, we need to create that class and configure it in the `package.manifest`. - -In `package.manifest`, we point to the path of the angular controller that we are creating in the next step. - -```json -{ - "javascript": [ - "~/App_Plugins/TwoFactorProviders/twoFactorProviderGoogleAuthenticator.controller.js" - ] -} -``` - -And we create the controller in that location: - -```javascript -!(function () { - "use strict"; - - const googleTwoFactorProviderCtrl = [ - '$scope', 'twoFactorLoginResource', 'notificationsService', - function ($scope, twoFactorLoginResource, notificationsService) { - const vm = this; - - vm.title = "Setup Google Authenticator on " + $scope.model?.user?.name; - vm.providerName = $scope.model?.providerName; - vm.qrCodeImageUrl = ""; - vm.secret = ""; - vm.code = ""; - vm.authForm = {}; - vm.buttonState = "init"; - - vm.close = close; - vm.validateAndSave = validateAndSave; - - function init() { - vm.buttonState = "init"; - twoFactorLoginResource.setupInfo(vm.providerName) - .then(function (response) { - // This response is the model I defined to be returned from ITwoFactorProvider.GetSetupDataAsync - vm.qrCodeImageUrl = response.qrCodeSetupImageUrl; - vm.secret = response.secret; - }) - .catch(function () { - notificationsService.error("Could not fetch login info"); - }); - } - - function validateAndSave() { - vm.authForm.token.$setValidity("token", true); - vm.buttonState = "busy"; - - twoFactorLoginResource.validateAndSave(vm.providerName, vm.secret, vm.code) - .then(function (successful) { - - if (successful) { - notificationsService.success("Two-factor authentication has successfully been enabled"); - vm.buttonState = "success"; - close(); - } else { - vm.authForm.token.$setValidity("token", false); - vm.buttonState = "error"; - } - - }) - .catch(function (error) { - notificationsService.error(error); - vm.buttonState = "error"; - }); - } - - function close() { - if ($scope.model.close) { - $scope.model.close(); - } - } - - init(); - } - ]; - - angular.module("umbraco").controller("CustomCode.TwoFactorProviderGoogleAuthenticator", googleTwoFactorProviderCtrl); -})(); -``` - -At this point, the 2FA is active, but no users have set up 2FA yet. - -Each user can now enable the configured 2fa providers on their user. This can be done from the user panel by clicking the user avatar. - -![User panel](images/user-panel.png) - -When clicking the `Configure Two-Factor` button, a new panel is shown, listing all enabled two-factor providers. - -![Configure 2fa](images/configure-2fa.png) - -When clicking `Enable` on one of these, the configured view for the specific provider will be shown - -![Enable 2fa](images/enable-2fa.png) - -When the authenticator is enabled correctly, a disable button is shown instead. - -![Disable 2fa](images/disable-2fa.png) - -To disable the two-factor authentication on your user, it is required to enter the verification code, otherwise, admins are allowed to disable providers on other users. - -![Verify disable](images/verify-disable.png) - -While the 2FA is enabled, the user will be presented with this screen after entering the username and password. ![Verify disable](images/login-2fa.png) - -## Notification when 2FA is requested for a user - -When a 2FA login is requested for a user, the `UserTwoFactorRequestedNotification` is published. This notification can also be used to send the user a one-time password via e-mail or phone, even though these 2FA types are [not considered secure](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/mfa?view=aspnetcore-6.0#mfa-sms) as App Authentication, it is still a massive improvement compared to no 2FA. diff --git a/10/umbraco-cms/reference/templating/README.md b/10/umbraco-cms/reference/templating/README.md deleted file mode 100644 index b7f776faa79..00000000000 --- a/10/umbraco-cms/reference/templating/README.md +++ /dev/null @@ -1,28 +0,0 @@ ---- - - ---- - -# Templating - -_Templating in Umbraco consists of 3 larger concepts, namely Templates (Views), Partials (Partial Views) and Macros (Macro Partials). Templates are used for the HTML layout of your pages. Partials can be included in your templates for shared functionality across different page templates. Macros can be used for reusable dynamic components that can be controlled by editors to embed functionality into the grid or rich text areas._ - -## Templating technology - -Umbraco uses ASP.Net MVC Views for implementing templates. - -{% hint style="info" %} -The WebForms (masterpages) and Dynamic Razor approaches to templating are still available in Umbraco version 7 but have been removed in Umbraco version 8. -{% endhint %} - -### [Working with MVC (views, razor, etc...)](mvc/) - -Describes how to work with MVC views, the razor syntax and APIs available. It also describes how to create forms, has some step-by-step guides and other advanced techniques. - -## [Macros](macros/) - -Describes how to set up a macro, use macro parameters & configuring caching. Defines the different types of macros and provides details on the different macro engine APIs and their usage. - -## [Models Builder](modelsbuilder/) - -A tool that can generate a complete set of strongly-typed published content models for Umbraco. Models are available in controllers, views, anywhere. Runs either from the Umbraco UI, from the command line, or from Visual Studio. diff --git a/10/umbraco-cms/reference/templating/images/change-parent-template.png b/10/umbraco-cms/reference/templating/images/change-parent-template.png deleted file mode 100644 index 67915e175c3..00000000000 Binary files a/10/umbraco-cms/reference/templating/images/change-parent-template.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/images/create-nested-template.png b/10/umbraco-cms/reference/templating/images/create-nested-template.png deleted file mode 100644 index f309dba9bef..00000000000 Binary files a/10/umbraco-cms/reference/templating/images/create-nested-template.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/README.md b/10/umbraco-cms/reference/templating/macros/README.md deleted file mode 100644 index 212b808b440..00000000000 --- a/10/umbraco-cms/reference/templating/macros/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# Macros - -_Describes how to set up a macro, use macro parameters & configuring caching. Defines the different types of macros and provides details on the different macro engine APIs and their usage_ - -## What is a macro - -A macro is 'wrapper' for a reusable piece of functionality that you can utilize in different places throughout your site. - -You can use macros in your templates, like MVC Partial views - however they differ in that they can be configured to work with Parameters and Caching, that can be updated by editors via the Umbraco Backoffice. So if you allow a macro to be added to a Rich Text Editor or Grid cell, the editor, at the point of inserting the macro can supply the parameter values. - -For example imagine adding an Image Gallery within a rich text editor, and at the point of insertion 'picking' the images to display. - -![Insert Image Carousel](images/Image-Carousel-Macro.png) - -Define the parameters - -![Define the parameters](images/macro-parameter-editor-v8.png) - -Using in a Rich Text Area - -A Rich Text Editor should be enabled with macros in the toolbar to allow inserting macros. - -![Enable macro toolbar in Rich Text Area](images/rte-macro.png) - -Rich Text Area with macro toolbar option - -![Macro toolbar option in Rich Text Area](images/rte-macro-toolbar.png) - -Insert the macro into a Rich Text Area - -![Insert the macro into a Rich Text Area](images/pick-images-for-macro-example-v8.png) - -The same implementation logic can be used in lots of different places on your site, and the editor can customise the output by choosing different parameters. - -## Implementing a Macro - -Macros can be implemented using an MVC Partial View - [Partial View Macros](partial-view-macros.md). It uses the exact same syntax and objects as [MVC views](../mvc/). - -## Rendering Macros - -Here's a basic method to render macros: - -```csharp -@await Umbraco.RenderMacroAsync("myMacroAlias") -``` - -### Rendering Macros with Parameters - -This renders a macro with some parameters using an anonymous object: - -```csharp -@await Umbraco.RenderMacroAsync("myMacroAlias", new { name = "Ned", age = 28 }) -``` - -This renders a macro with some parameters using a dictionary - -```csharp -@await Umbraco.RenderMacroAsync("myMacroAlias", new Dictionary {{ "name", "Ned"}, { "age", 27}}) -``` - -#### Meaning of all the symbols - -**Request Collection** - -To retrieve a value from the request collection such as a query string parameter we specify it by prefixing with an "@" symbol. - -To get a query string parameter with the key "productId" we would specify our parameter like this **\[@productId]** - -**Document Type Property** - -Document type properties are specified by a leading "#" and then the alias of the document property. - -To pass a property with the alias "bodyText" we would specify **\[#bodyText]** in the parameter value. - -**Recursive Document Type Property** - -Recursive Document type properties are specified by a leading "$" and then the alias of the document property. - -Umbraco resolves recursive parameters by looking at the current page for a value and then traversing up the content tree until a value with that alias is found. - -**Session Collection** - -Retrieve values from the session collection or cookies by prefixing with a "%" symbol. - -To retrieve a value with the key "memberId" from the session collection we would specify our Macro parameter value as **\[%memberId]** - -### Caching Macro Output - -For long running macros that return the same results, caching boosts site performance, you can specify caching levels for the Macro in the backoffice. - -Options are: - -* Cache by Period - set the number of seconds to cache the output of the Macro for -* Cache by Page - Whether to create a different cached instance of the macro for each page (think breadcrumb - you wouldn't want the same breadcrumb on every page) -* Cache Personalized - whether to create a difference cached instance of the macro for each site visitor (if your Macro says 'Hi Niels' using the currently logged in Members name, you wouldn't want this cached to be the same for every visitor to the site, unless they were all called Niels) diff --git a/10/umbraco-cms/reference/templating/macros/images/Image-Carousel-Macro.png b/10/umbraco-cms/reference/templating/macros/images/Image-Carousel-Macro.png deleted file mode 100644 index 22fdc266a8c..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/Image-Carousel-Macro.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/create-macro-from-type.png b/10/umbraco-cms/reference/templating/macros/images/create-macro-from-type.png deleted file mode 100644 index 7062db09db0..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/create-macro-from-type.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/create-macro-tree-8.png b/10/umbraco-cms/reference/templating/macros/images/create-macro-tree-8.png deleted file mode 100644 index 29c91f246cb..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/create-macro-tree-8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/create-macro-tree.png b/10/umbraco-cms/reference/templating/macros/images/create-macro-tree.png deleted file mode 100644 index b4d7d6ecfb2..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/create-macro-tree.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/image-carousel-macro-parameter.png b/10/umbraco-cms/reference/templating/macros/images/image-carousel-macro-parameter.png deleted file mode 100644 index 3840b2385e8..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/image-carousel-macro-parameter.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/image-carousel-macro-v8.PNG b/10/umbraco-cms/reference/templating/macros/images/image-carousel-macro-v8.PNG deleted file mode 100644 index a19a3992bfc..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/image-carousel-macro-v8.PNG and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/macro-editor-8.png b/10/umbraco-cms/reference/templating/macros/images/macro-editor-8.png deleted file mode 100644 index a123b1af06d..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/macro-editor-8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/macro-editor.png b/10/umbraco-cms/reference/templating/macros/images/macro-editor.png deleted file mode 100644 index 3cdd9b4b300..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/macro-editor.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/macro-parameter-editor-v8.png b/10/umbraco-cms/reference/templating/macros/images/macro-parameter-editor-v8.png deleted file mode 100644 index 0d88bc74b34..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/macro-parameter-editor-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/macro-parameter-editor.png b/10/umbraco-cms/reference/templating/macros/images/macro-parameter-editor.png deleted file mode 100644 index 35c4e8f6df5..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/macro-parameter-editor.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/macro-parameters-v8.png b/10/umbraco-cms/reference/templating/macros/images/macro-parameters-v8.png deleted file mode 100644 index 64c97a7f1a9..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/macro-parameters-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/partial-view-macro-files-8.png b/10/umbraco-cms/reference/templating/macros/images/partial-view-macro-files-8.png deleted file mode 100644 index 5b0753f1c8f..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/partial-view-macro-files-8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/pick-images-for-macro-example-v8.png b/10/umbraco-cms/reference/templating/macros/images/pick-images-for-macro-example-v8.png deleted file mode 100644 index 12bbff1cd2b..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/pick-images-for-macro-example-v8.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/pick-images-for-macro-example.png b/10/umbraco-cms/reference/templating/macros/images/pick-images-for-macro-example.png deleted file mode 100644 index 29c3d429311..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/pick-images-for-macro-example.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/rte-macro-toolbar.png b/10/umbraco-cms/reference/templating/macros/images/rte-macro-toolbar.png deleted file mode 100644 index 905dcb6def2..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/rte-macro-toolbar.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/images/rte-macro.png b/10/umbraco-cms/reference/templating/macros/images/rte-macro.png deleted file mode 100644 index 7f2b2518a5e..00000000000 Binary files a/10/umbraco-cms/reference/templating/macros/images/rte-macro.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/macros/managing-macros.md b/10/umbraco-cms/reference/templating/macros/managing-macros.md deleted file mode 100644 index bee577496ae..00000000000 --- a/10/umbraco-cms/reference/templating/macros/managing-macros.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -needsv9Update: 'true' ---- - -# Managing macros - -In this article you can learn how to create and update a Macro, as well as how to configure its parameters. - -## Creating macros - -There are a couple of ways to create a macro. - -### Manually - -The first way is to manually create a macro, by right-clicking the Macro folder in the Settings section: - -![Create macro](images/create-macro-tree-8.png) - -Give it a name in the dialog screen, and you'll be presented with the macro editor. - -### Partial View Macro files - -The second option is to create the macro through **Partial View Macro Files**. - -![Partial View Macro files dialog](images/partial-view-macro-files-8.png) - -The dialog provides the following options: - -* New partial view macro: Will give you an empty macro with an associated empty partial view file -* New partial view macro (without macro): Will give you a partial view, without an associated macro -* New partial view macro from snippet...: Will give you the option to choose between a pre-defined set, including a macro and a partial view with a code snippet -* Folder...: Will give you the option to create a folder below "Partial View Macro Files" - -## Macro Editor - -The macro editor view comes with a set of configuration options. - -![Macro editor](images/macro-editor-8.png) - -### Macro partial view - -Associate the macro with a partial view. This will already have been configured if you created the macro through the second option described above, where a Partial view was created along with the macro. - -### Editor settings - -> Use in rich text editor and the grid - -If selected will allow an editor to insert this macro in to a Rich Text Editor and/or into a Grid editor. - -## Caching options - -> Cache period - -Defines how many seconds the macro output will be cached for once it is rendered - -> Cache by page - -If selected, then the macro will be cached based on the current page it is rendered on. This is useful if your macro has content that is dynamic to the current page it is being rendered on. If your macro's output is static (the same) no matter what page it is rendered on then it is better to not check this box. - -> Cache personalized - -Similar to the 'Cache by page', this will cache the output of a macro based on a member that is logged in. If your macro is static (the same) no matter what member is logged in, or if your website does not have membership then it is better to not check this box. - -## Macro parameters - -Macro parameters can be used to change the output of a macro at runtime. Macro parameters are often used as a way for your editors to change the output of a macro when they insert them into rich text editors. As an example, suppose you have a widget that displays a list of links which are children of a particular content item. You could define a macro parameter that indicates for which content item to render child links for and your editor can select this content item when inserting the macro into the rich text editor. - -The macro parameter dialog looks like this: - -![Macro editor](images/macro-parameters-v8.png) - -Here you can add/modify/remove macro parameters. - -### Default macro parameter types - -This list defines the different types of macro parameters: - -* Checkbox(`Umbraco.TrueFalse`) - A true/false value -* Content Type picker (`contentType`) - Choose a type from existing Document Types -* Decimal (`Umbraco.Decimal`) - accepts only numbers -* Email address (`Umbraco.EmailAddress`) - validates to valid email addresses -* Multiple Content Picker (`Umbraco.MultiNodeTreePicker`) - pick 1 or more nodes from the Content tree -* Multiple Content Type Picker (`contentTypeMultiple`) - pick 1 or more types from existing Document Types -* Multiple Media Picker (`Umbraco.MultipleMediaPicker`) - pick 1 or more media items -* Multiple Property Type Picker (`propertyTypePickerMultiple`) - pick 1 or more from existing property types -* Multiple Tab Picker (`tabPickerMultiple`) - pick 1 or more from existing tabs -* Numeric (`Umbraco.Integer`) - accepts only numbers -* Property Type Picker (`propertyTypePicker`) - choose property from existing property types -* Tab picker (`tabPicker`) - select 1 from list of existing tabs -* Textarea (`Umbraco.TextArea`) - multiple lines of text -* Textbox (`Umbraco.TextBox`) - single line of text -* Media picker (`Umbraco.MediaPicker`) - select a single media item -* Content Picker (`Umbraco.ContentPicker`) - select a single content node from the Content tree -* Form Picker (`UmbracoForms.FormsPicker`) - choose from existing Umbraco Forms -* Forms Theme Picker (`UmbracoForms.ThemePicker`) - choose from existing Forms Themes diff --git a/10/umbraco-cms/reference/templating/macros/partial-view-macros.md b/10/umbraco-cms/reference/templating/macros/partial-view-macros.md deleted file mode 100644 index 4ce1c12d6d0..00000000000 --- a/10/umbraco-cms/reference/templating/macros/partial-view-macros.md +++ /dev/null @@ -1,68 +0,0 @@ -# Partial View Macros - -Partial View Macros are the recommended macro type to use in Umbraco. They work in both MVC and Webforms and use the unified query syntax that is available via the `UmbracoHelper`. - -## View/Model Type - -All Partial View Macro views inherit from `Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage` and the header of each Partial View Macro file will contain: - -```csharp -@inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage -``` - -The model type for a Partial View Macro is `Umbraco.Cms.Core.Models.PartialViewMacroModel`. This contains all of the properties you need to render out content alongside some additional properties about the macro itself: - -* MacroName -* MacroAlias -* MacroId -* MacroParameters - -## File Information - -By default, Partial View Macros are stored in this folder: - -> \~/Views/MacroPartials - -However, if you are bundling up Partial View Macros as part of a package, they can also exist in this folder: - -> \~/App\_Plugins/\[YourPackageName]/Views/MacroPartials - -Since Partial View Macros are a normal MVC partial view, their file extension is **cshtml**. All Partial View Macro views inherit from the following view class: - -```csharp -Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage -``` - -Therefore, all files will contain the header (which is done automatically for you if creating Partial View Macros via the Umbraco backoffice): - -```csharp -@inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage -``` - -## Accessing Content - -The syntax in Partial View Macros is similar to the [**MVC View**](../mvc/views.md) syntax. In fact, they are driven by the exact same engine as MVC Views. - -You can use @CurrentPage, @Model.Content, @Umbraco, ... - -## Accessing Macro Parameters - -You can access the macro's parameters using the: - -* `MacroParameters` property on the model which is of type `IDictionary`: - - ```csharp - var myParam = Model.MacroParameters["aliasOfTheMacroParameter"]; - ``` -* Typed GetParameterValue method in `Umbraco.Cms.Core.Models` namespace: - - ```csharp - @using Umbraco.Cms.Core.Models; - var myParam = Model.GetParameterValue("aliasOfTheMacroParameter"); - ``` -* Typed GetParameterValue method with the default value fallback: - - ```csharp - @using Umbraco.Cms.Core.Models; - var myParam = Model.GetParameterValue("aliasOfTheMacroParameter", "default value if parameter value has not been set"); - ``` diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/README.md b/10/umbraco-cms/reference/templating/modelsbuilder/README.md deleted file mode 100644 index e62d0229b2d..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/README.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -meta.Title: "Modelsbuilder Reference" -description: "Modelsbuilder reference" ---- - - -# Umbraco Models Builder - -The Models builder is a tool that can generate a complete set of strongly-typed published content models for Umbraco. Models are available in both controllers and views. - -* [Introduction](introduction.md) -* [Configuration](configuration.md) -* [Builder Modes](builder-modes.md) -* [Understand and Extend Models](understand-and-extend.md) -* [Using Interfaces](using-interfaces.md) -* [Tips and Tricks](coolthingswithmodels.md) diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/builder-modes.md b/10/umbraco-cms/reference/templating/modelsbuilder/builder-modes.md deleted file mode 100644 index 1ed5646a226..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/builder-modes.md +++ /dev/null @@ -1,50 +0,0 @@ ---- - - -meta.Title: "Modelsbuilder Modes" -description: "Modelsbuilder modes" ---- - -# Builder Modes - -Models Builder can be used in different modes: - -* InMemory models -* SourceCode models - -The mode is indicated by the `Umbraco:CMS:ModelsBuilder:ModelsMode` key in the configuration (`appsettings.json` files). - -## In memory - -Corresponds to the `InMemoryAuto` setting value. - -With **InMemory** models, models are generated and compiled on the fly, in memory, at runtime. They are available in views exclusively. - -This is for a setup that exclusively uses the Umbraco backoffice, and do not use custom code such as controllers. Whenever a content type is modified, models are updated without restarting Umbraco (in the same way .cshtml views are recompiled). - -Generation *can* fail for various reasons, in which case Umbraco will run without models (and front-end views fail to render). Umbraco's log file should contain all details about what prevented the generation, but it is probably faster to check the Models Builder dashboard, which should report the last error that was encountered, if any. - -Models Builder maintains some files in `~/umbraco/Data/TEMP/InMemoryAuto`: - -* `models.generated.cs` contains the generated models code -* `all.generated.cs` contains the compiled code (models merged with non-generated files) -* `models.hash` contains a hash code of the content types -* `all.dll.path` contains the path to the compiled DLL file containing all the models -* `Compiled/generated.cs{GUID}.dll` the dll containing all the generated models -* `models.err` contains the last generation error information, if any - -The `models.hash` file is used when Umbraco restarts, to figure out whether models have changed and need to be re-generated. Otherwise, the local `models.generated.cs` file is reused. - -## SourceCode Models - -Corresponds to the `SourceCodeManual` and `SourceCodeAuto` setting values. - -With **SourceCode** models, models are generated in the `~/umbraco/models` directory, and that is all. It is then up to you to decide how to compile the models (e.g. by including them in a Visual Studio solution). - -Generation *can* fail for various reasons, in which case no models are generated. Umbraco's log file should contain all details about what prevented the generation, but it is probably faster to check the Models Builder dashboard, which should report the last error that was encountered, if any. - -The modelsbuilder works much in the same way whether using `SourceCodeManual` or `SourceCodeAuto`. The only real difference between the two are that with `SourceCodeManual` you must manually trigger the generation of the models from the models builder dashboard, whereas with `SourceCodeAuto` the models are automatically generated whenever content types change. - -## API models and Dll Models - -These modes are not available in the embedded version of Models Builder. See the full version of [ModelsBuilder](https://github.com/zpqrtbnk/Zbu.ModelsBuilder). diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/configuration.md b/10/umbraco-cms/reference/templating/modelsbuilder/configuration.md deleted file mode 100644 index 968bb413639..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/configuration.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -meta.Title: ModelsBuilder Configuration -description: Explanation of how to configure models builder ---- - -# Configuration - -The following configuration option can be set in the application settings (in the `appsettings.json` file): - -* `Umbraco.CMS.ModelsBuilder.ModelsMode` determines how Models Builder generates models. Valid values are: - * `Nothing`: Do not generate models. - * `InMemoryAuto`(default): Generate models in a dynamic in-memory assembly. - * `SourceCodeManual`: Generate models in `~/umbraco/models` (but do not compile them) whenever the user clicks the "Generate models" button on the Models Builder dashboard in the Settings section. - * `SourceCodeAuto`: Generate models in `~/umbraco/models` (but do not compile them) anytime a content type changes. -* `Umbraco.CMS.ModelsBuilder.ModelsNamespace` (string, default is `Umbraco.Cms.Web.Common.PublishedModels`) specifies the generated models' namespace. -* `Umbraco.CMS.ModelsBuilder.FlagOutOfDateModels` (bool, default is `true`) indicates whether out-of-date models (i.e. after a content type or data type has been modified) should be flagged. -* `Umbraco.CMS.ModelsBuilder.ModelsDirectory` (string, default is `~/umbraco/models`) indicates where to generate models and manage all files. Has to be a virtual directory (starting with `~/`) below the website root (see also: `AcceptUnsafeModelsDirectory` below). -* `Umbraco.CMS.ModelsBuilder.AcceptUnsafeModelsDirectory` (bool, default is `false`) indicates that the directory indicated in `ModelsDirectory` is allowed to be outside the website root (e.g. `~/../../some/place`). Due to this being a potential security risk, it is not allowed by default. -* `Umbraco.CMS.ModelsBuilder.DebugLevel` (int, default is zero) indicates the debug level. Set to greater than zero to enable detailed logging. For internal / development use. - -## Example Configuration - -The example below shows an example configuration using the SourceCodeManual mode. - -```json -{ - "$schema": "https://json.schemastore.org/appsettings.json", - "Umbraco": { - "CMS": { - "ModelsBuilder": { - "ModelsMode": "SourceCodeManual" - } - } - } -} -``` - -{% hint style="info" %} -It is recommended to generate models in your development environment only and change the ModelsMode to `Nothing` for your staging and production environments. -{% endhint %} - -## Models Builder Dashboard - -Models Builder ships with a dashboard in the _Settings_ section of Umbraco's backoffice. The dashboard does three things: - -* Details on how Models Builder is configured -* Provides a way to generate models (in SourceCodeManual mode only) -* Reports the last error (if any) that would have prevented models from being properly generated - -![Models Builder Dashboard](images/ModelsBuilderDashboard-v9.png) diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/coolthingswithmodels.md b/10/umbraco-cms/reference/templating/modelsbuilder/coolthingswithmodels.md deleted file mode 100644 index e444fa87008..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/coolthingswithmodels.md +++ /dev/null @@ -1,36 +0,0 @@ ---- - - -meta.Title: "Cool Things to do With Models" -description: "Cool things you can do with models" ---- -# Cool things you can do with strongly-typed models - -It's possible with Razor to define functions for rendering HTML, we can leverage our strongly typed models when doing this, and even provide overloads for different types of models, that will automatically called for different models using `dynamic` - -```csharp -@functions -{ - // Declare how to render a news item - void RenderContent(NewsItem item) - { -
News! @item.Title
- } - - // Declare how to render a product - void RenderContent(Product item) - { -
Product! @product.Name cheap at @product.Price
- } -} - -@{ - RenderContent((dynamic) Model); -} -``` - -Now, it's not recommended to create a single template and doing all the rendering via razor function, but it can be quite nifty for rendering search results, and so on. - -A thing that's important to note here is that `RenderContent` is called from a codeblock, and not as `@RenderContent((dynamic) Model);` the reason for this is that if you try to use the latter, razor will expect for the function to return something for it to render. - -By casting the strongly-typed to a dynamic when calling the **RenderContent** method, you tell C# to do late runtime binding and pick the proper **RenderContent** implementation depending on the actual CLR type of the **content** object. Using dynamic here is OK and will not pollute the rest of the code. diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/images/ModelsBuilderDashboard-v9.png b/10/umbraco-cms/reference/templating/modelsbuilder/images/ModelsBuilderDashboard-v9.png deleted file mode 100644 index b3c9375cfba..00000000000 Binary files a/10/umbraco-cms/reference/templating/modelsbuilder/images/ModelsBuilderDashboard-v9.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/images/ModelsBuilderDashboard.png b/10/umbraco-cms/reference/templating/modelsbuilder/images/ModelsBuilderDashboard.png deleted file mode 100644 index 1cf34344627..00000000000 Binary files a/10/umbraco-cms/reference/templating/modelsbuilder/images/ModelsBuilderDashboard.png and /dev/null differ diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/introduction.md b/10/umbraco-cms/reference/templating/modelsbuilder/introduction.md deleted file mode 100644 index 2047892d890..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/introduction.md +++ /dev/null @@ -1,124 +0,0 @@ ---- - - -meta.Title: "Modelsbuilder Introduction" -description: "Modelsbuilder introduction" ---- - -# Umbraco Models Builder Introduction - -Models Builder is a tool that can generate a complete set of strongly-typed published content models for Umbraco. By default, a slimmed down version of Models Builder is embedded with the main Umbraco distribution. - -Models can be used anywhere that content is retrieved from the content cache, i.e. in MVC views, controllers, etc. In other words, when using the Models Builder, the content cache does not return `IPublishedContent` objects anymore, but strongly typed models, implementing `IPublishedContent`. - -For each content, media and member type in the Umbraco setup, the generator creates a `*.generated.cs` file, corresponding to the type. For instance, a document type with a textstring property named Title, and a rich text editor named BodyText will look like this: - -```csharp -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Umbraco.ModelsBuilder.Embedded v9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293 -// -// Changes to this file will be lost if the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Linq.Expressions; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Infrastructure.ModelsBuilder; -using Umbraco.Cms.Core; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Web.Common.PublishedModels -{ -/// NewsItem -[PublishedModel("newsItem")] -public partial class NewsItem : PublishedContentModel -{ - // helpers -#pragma warning disable 0109 // new is redundant - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293")] - public new const string ModelTypeAlias = "newsItem"; - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293")] - public new const PublishedItemType ModelItemType = PublishedItemType.Content; - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293")] - public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor) - => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias); - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293")] - public static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector) - => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector); -#pragma warning restore 0109 - - private IPublishedValueFallback _publishedValueFallback; - - // ctor - public NewsItem(IPublishedContent content, IPublishedValueFallback publishedValueFallback) - : base(content, publishedValueFallback) - { - _publishedValueFallback = publishedValueFallback; - } - - // properties - - /// - /// BodyText - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293")] - [ImplementPropertyType("bodyText")] - public virtual global::Umbraco.Cms.Core.Strings.IHtmlEncodedString BodyText => this.Value(_publishedValueFallback, "bodyText"); - - /// - /// Title - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Umbraco.ModelsBuilder.Embedded", "9.0.0-beta003+b07f6519e7a1c890b534502982612ce6b3fea293")] - [ImplementPropertyType("title")] - public virtual string Title => this.Value(_publishedValueFallback, "title"); - } -} -``` - -Now since this is an automatically generated file, it's a bit messy, the important part is that it has all the properties defined and strongly typed: - -```c# -public virtual global::Umbraco.Cms.Core.Strings.IHtmlEncodedString BodyText => this.Value(_publishedValueFallback, "bodyText"); -``` - -And: - -```c# -public virtual string Title => this.Value(_publishedValueFallback, "title"); -``` - -Umbraco's content cache returns these objects _natively_: No need to map, convert or anything; the following code runs: - -```csharp -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -

@Model.Title

-

@Model.BodyText

-``` - -{% hint style="info" %} -If your view inherits from `UmbracoViewPage` then the model is the content item itself and the syntax is `@Model.Title`. -{% endhint %} - -Models Builder respects the content types' inheritance tree, i.e. models inherit from each other if required, and mixins (content type compositions) are represented by interfaces. - -Models Builder is a "_code-after_*_" solution. It only generates code from content types that already exist in Umbraco. It is not a "_code-first_" solution - code-first is a much more complex question. - -And once you are using strongly typed models, there are some [cool things](coolthingswithmodels.md) that you can do. - -## Installing - -The Models Builder is by default embedded in Umbraco. If you need more complex features than what is provided, you still need to add the full package. However, as of right now the package is not updated to be able to handle NetCore or Umbraco V9. - -Check [the official releases on the Models Builder GitHub repository](https://github.com/zpqrtbnk/Zbu.ModelsBuilder/releases) for more details. - -## Documentation - -At the core of the strongly typed models "experience" is the `IPublishedModelFactory` interface. This interface is part of the Umbraco core codebase. It is responsible for mapping the internal `IPublishedContent` implementations returned by the content cache, to strongly typed models. There is a default factory shipped with Umbraco and it is possible to replace this by custom implementations. When using the default factory, models do _not_ necessarily need to be generated by Models Builder. - -Models Builder is one way to generate models for the default, built-in factory. Models can be generated automatically or straight from the Settings section of the Umbraco backoffice, for more info see [builder modes](builder-modes.md). diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/understand-and-extend.md b/10/umbraco-cms/reference/templating/modelsbuilder/understand-and-extend.md deleted file mode 100644 index 12d2dc28c24..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/understand-and-extend.md +++ /dev/null @@ -1,225 +0,0 @@ ---- -description: Understanding and Extending ModelsBuilder in Umbraco ---- - - -# Introduction - -Umbraco’s Models Builder automatically generates strongly typed models for content types, allowing developers to work with Umbraco data in a structured and efficient manner. This article explains how models are generated, how composition and inheritance work, and best practices for extending models without causing issues. - -## Models Generation Process - -Models Builder generates each content type as a partial class. For example, a content type named `TextPage` results in a `TextPage.generated.cs` file with a structure like this: - -```csharp -/// TextPage -[PublishedModel("textPage")] -public partial class TextPage : PublishedContentModel -{ - //static helpers - public new const string ModelTypeAlias = "textPage"; - - public new const PublishedItemType ModelItemType = PublishedItemType.Content; - - public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor) - => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias); - - public static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector) - => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector); - - private IPublishedValueFallback _publishedValueFallback; - - //constructor - public TextPage(IPublishedContent content, IPublishedValueFallback publishedValueFallback) - : base(content, publishedValueFallback) - { - _publishedValueFallback = publishedValueFallback; - } - - // properties - - /// - /// Header - /// - [ImplementPropertyType("header")] - public virtual string Header => this.Value(_publishedValueFallback, "header"); -} -``` - -In the above code: - -* The model includes a constructor and static helpers to fetch the content type (`PublishedContentType`) and property type (`PublishedPropertyType`). -* The most important part is the property definition (`Header`), which retrieve values from Umbraco. - -You can use helper methods to access content and property types: - -```csharp -var contentType = TextPage.GetModelContentType(); // is a PublishedContentType -var propertyType = TextPage.GetModelPropertyType(x => x.Header); // is a PublishedPropertyType -``` - -## Composition and Inheritance - -### Composition - -Umbraco content types can be composed of multiple other content types. Unlike traditional C# inheritance, Umbraco allows a content type to inherit properties from multiple sources. - -For example, a `TextPage` might be composed of: - -* **MetaInfo** content type (inherits `Author` and `Keywords` properties). -* **PageInfo** content type (inherits `Title` and `MainImage` properties). - -Each content type in a composition is generated both as a class and as an interface. The `MetaInfo` content type would be generated as: - -```csharp -// The composition interface -public partial interface IMetaInfo : IPublishedContent -{ - public string Author { get; } - public IEnumerable Keywords { get; } -} - -// The composition class -public partial class MetaInfo : PublishedContentModel -{ - // the "static mixin getter" for the property - public static string GetAuthor(IMetaInfo that) - { - return that.GetPropertyValue("author"); - } - - public string Author { get { return MetaInfo.GetAuthor(this, _publishedValueFallback); } } -} -``` - -And the `TextPage` model would be generated as: - -```csharp -public partial class TextPage : PublishedContentModel, IMetaInfo -{ - // get the property value from the "static mixin getter" - public string Author { get { return MetaInfo.GetAuthor(this, _publishedValueFallback); } } -} -``` - -### Inheritance - -In addition to composition, content types can have a parent-child relationship. In the Umbraco backoffice, a content type appears underneath its parent. - -By convention, a content type is always **composed of its parent** and therefore inherits its properties. However, the parent content type is treated differently, and the child content type *directly inherits* (as in C# inheritance) from the parent class. - -If `AboutPage` is a child of TextPage, its generated model would inherit directly from `TextPage`: - -```csharp -// Note: Inherits from TextPage -public partial class AboutPage : TextPage -{ - ... -} -``` - -## Extending Models - -Since models are partial classes, developers can extend them by adding additional properties. - -For Example: - -```csharp -public partial class TextPage -{ - public string WrappedHeader => $"[{Header}]"; -} -``` - -Models Builder does not recognize custom partial classes during regeneration. If your custom class conflicts with the generated class (e.g., overriding a constructor), it will cause compilation errors. - -Overloaded constructors will not be used because models are always instantiated using the default constructor. - -For more complex customizations, use the full version of [Models Builder](https://github.com/zpqrtbnk/Zbu.ModelsBuilder). - -## Best Practices for Extending Models - -Extending models should be used to add stateless, local features to models. It should not be used to transform *content* models into view models or manage trees of content. - -### Good practices - -A customer has "posts" that has two "release date" properties. One is a true date picker property and is used to specify an actual date and to order the posts. The other is a string that is used to specify dates such as "Summer 2015" or "Q1 2016". Alongside the title of the post, the customer wants to display the text date, if present, else the actual date. If none of those are present, the Umbraco update date should be used. Keep in mind that each view can contain code to deal with the situation, but it is much more efficient to extend the `Post` model: - -```csharp - public partial class Post - { - public string DisplayDate - { - get - { - if(!TextDate.IsNullOrWhiteSpace()) - { - return TextDate; - } - - if (ActualDate != default) - { - return ActualDate.ToString(); - } - - return UpdateDate.ToString(); - } - } - } -``` - -Simplified view: - -```csharp -
-
@Model.Title
-
@Model.DisplayDate
-
-``` - -### Bad practices - -Because, by default, the content object is passed to views, one can be tempted to add view-related properties to the model. Some properties that do *not* belong to a *content* model would be: - -* A `HomePage` property that retrieves the "home page" content item. -* A `Menu` property that lists navigation items. - -Generally speaking, anything that is tied to the current request, or that depends on more than the modeled content, is a bad idea. There are much cleaner solutions, such as using true *view model* classes that would be populated by a true controller and look like: - -```csharp -public class TextPageViewModel -{ - public TextPage Content; // The content model - public HomePage HomePage; // The home page content model - public IEnumerable Menu; // The menu content models -} -``` - -One can also extend Umbraco's views to provide a special view helper that gives access to important elements of the website: - -```csharp -@MySite.HomePage.Title -``` - -### Ugly practices - -The model's scope and lifecycle are *unspecified*. It may exist only for your request or be cached and shared across all requests. - -The code has a major issue: the `TextPage` model caches a `HomePageDocument` model that will not update when the home page is re-published. - -```csharp -private HomePageDocument _homePage; -public HomePageDocument HomePage -{ - get - { - if (_homePage is null) - { - _homePage = this.AncestorOrSelf(1); - } - return _homePage; - } -} -``` - -As a rule of thumb, models should never reference and cache other models. diff --git a/10/umbraco-cms/reference/templating/modelsbuilder/using-interfaces.md b/10/umbraco-cms/reference/templating/modelsbuilder/using-interfaces.md deleted file mode 100644 index 72229ecf2f3..00000000000 --- a/10/umbraco-cms/reference/templating/modelsbuilder/using-interfaces.md +++ /dev/null @@ -1,37 +0,0 @@ ---- - - -meta.Title: "Using Modelsbuilder interfaces" -description: "Using interfaces with modelsbuilder" ---- - -# Using Interfaces - -When using compositions, Models Builder generates an interface for the composed model, which enables us to not have to switch back to using `Value()` for the composed properties. - -A common use-case for this is if you have a separate composition for the "SEO properties" `Page Title` and `Page Description`. - -You would usually use this composition on both your `Home` and `Textpage` document types. Since both `Home` and `Textpage` will implement the generated `ISeoProperties` interface, you will still be able to use the simpler models builder syntax (e.g. `Model.PageTitle`). - -However, you won't be able to use the nice models builder syntax on any master template, since a master template needs to be bound to a generic `IPublishedContent`. So you'd have to resort to the *ever-so-slightly* clumsier `Model.Value("pageTitle")` syntax to render these properties. It is possible to solve this issue of master templating, by using partial views, to render the SEO specific properties. - -## Render with a partial - -If you create a partial and change the first line to use the *interface name* for the model binding, you can use the nice Models Builder syntax when rendering the properties, like this: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@Model.PageTitle - -``` - -You can then render the partial from your Master Template with something like this (assuming the partial is named `Metatags.cshtml`): - -```csharp - - @Html.Partial("Metatags") - -@RenderBody() -``` - -It's important to note though, that this master template will only work for content types that use the Seo Properties composition. diff --git a/10/umbraco-cms/reference/templating/mvc/README.md b/10/umbraco-cms/reference/templating/mvc/README.md deleted file mode 100644 index 80c908c5b49..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/README.md +++ /dev/null @@ -1,25 +0,0 @@ ---- - - ---- - -# Working with MVC in Umbraco - -_How to work with MVC templates in Umbraco_ - -## [Views](views.md) -Working with MVC Views and Razor syntax in Umbraco - -_[See some quick examples here](examples.md)_ - -## [Partial Views](partial-views.md) -Documentation covering how to use Partial Views. This is not documentation about using "[Partial View Macros](../macros/partial-view-macros.md)", this documentation relates to using native MVC partial views within Umbraco. - -## [Child Actions](child-actions.md) -Using MVC Child Actions in Umbraco - -## [ViewComponents](viewcomponents.md) -Using MVC Child Actions in Umbraco - -## [Querying](querying.md) -How to query for published data in your Views diff --git a/10/umbraco-cms/reference/templating/mvc/examples.md b/10/umbraco-cms/reference/templating/mvc/examples.md deleted file mode 100644 index c74f637a407..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/examples.md +++ /dev/null @@ -1,51 +0,0 @@ ---- - - ---- - -# View/Razor Examples - -_Lots of examples of using various techniques to render data in a view_ - -## Rendering the raw value of a field from IPublishedContent - -```csharp -@Model.Value("bodyContent") -``` - -## Rendering the converted value of a field from IPublishedContent - -```csharp -@Model.Value("amount") -@Model.Value("bodyContent") -``` - -## Rendering a macro - -```csharp -@Umbraco.RenderMacro("myMacroAlias") -``` - -## Rendering a macro with parameters using an anonymous object - -```csharp -@Umbraco.RenderMacro("myMacroAlias", new { name = "Ned", age = 28 }) -``` - -## Rendering a macro with parameters using a dictionary - -```csharp -@Umbraco.RenderMacro("myMacroAlias", new Dictionary {{ "name", "Ned"}, { "age", 27}}) -``` - -## Rendering some member data - -```csharp -@if(Members.IsLoggedIn()){ - var profile = Members.GetCurrentMemberProfileModel(); - var umbracomember = Members.GetByUsername(profile.UserName); - -

@umbracomember.Name

-

@umbracomember.Value("bio")

-} -``` diff --git a/10/umbraco-cms/reference/templating/mvc/forms.md b/10/umbraco-cms/reference/templating/mvc/forms.md deleted file mode 100644 index b134c02f107..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/forms.md +++ /dev/null @@ -1,13 +0,0 @@ ---- - - ---- - -# Creating Forms - -Creating an HTML form to submit data with MVC in Umbraco is possible in a few steps. - -If you want to create a Form: - -1. Using view models, views, controllers, and a handy HtmlHelper extension method called BeginUmbracoForm, see the [Creating Forms](../../../fundamentals/code/creating-forms.md) article. -2. Using Umbraco Forms, see the [Umbraco Forms Documentation](https://docs.umbraco.com/umbraco-forms/) article. diff --git a/10/umbraco-cms/reference/templating/mvc/partial-views.md b/10/umbraco-cms/reference/templating/mvc/partial-views.md deleted file mode 100644 index b57458f83bc..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/partial-views.md +++ /dev/null @@ -1,147 +0,0 @@ ---- - - ---- - -# Using MVC Partial Views in Umbraco - -_This section will show you how to use MVC Partial Views in Umbraco. Please note, this is documentation relating to the use of native MVC partial views, not '_[_Partial View Macros_](../macros/partial-view-macros.md)_'_ - -## Overview - -Using Partial Views in Umbraco is exactly the same as using Partial Views in a normal MVC project. There is detailed documentation on the Internet about [creating and using MVC partial views](https://www.asp.net/mvc/videos/mvc-2/how-do-i/how-do-i-work-with-data-in-aspnet-mvc-partial-views) - -Partial views allow you to re-use components between your views (templates). - -## View Locations - -The locations to store Partial Views when rendering in the Umbraco pipeline is: - -``` -~/Views/Partials -``` - -The standard MVC partial view locations will also work: - -``` -~/Views/Shared -~/Views/Render -``` - -The `~/Views/Render` location is valid because the controller that performs the rendering in the Umbraco codebase is the: `Umbraco.Cms.Web.Common.Controllers.RenderController` - -If however you are [Hijacking an Umbraco route](../../routing/custom-controllers.md) and specifying your own controller to do the execution, then your partial view location can also be: - -``` -~/Views/{YourControllerName} -``` - -## Example - -A quick example of a content item that has a template that renders out a partial view template for each of its child documents: - -The MVC template markup for the document: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@{ - Layout = null; -} - - - -@foreach(var page in Model.Children().Where(x => x.IsVisible())) - { -
- @Html.Partial("ChildItem", page) -
- } - - -``` - -The partial view (located at: `~/Views/Partials/ChildItem.cshtml`) - -```csharp -@model IPublishedContent -@Model.Name -``` - -## Strongly typed Partial Views - -Normally you would create a partial view by using the `@model MyModel` syntax. However, inside of Umbraco you will probably want to have access to the handy properties available on your normal Umbraco views like the Umbraco helper: `@Umbraco` and the Umbraco context: `@UmbracoContext`. The good news is that this is possible. Instead of using the `@model MyModel` syntax, you need to inherit from the correct view class, so do this instead: - -```csharp -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -``` - -By inheriting from this view, you'll have instant access to those handy properties and have your view created with a strongly typed custom model. - -Another case you might have is that you want your Partial View to be strongly typed with the same model type (`IPublishedContent`) as a normal template if you are passing around instances of IPublishedContent. To do this, have your partial view inherit from `Umbraco.Cms.Web.Common.Views.UmbracoViewPage` (like your normal templates). When you render your partial, a neat trick is that you can pass it an instance of `IPublishedContent`. For example: - -```csharp -@foreach(var child in Model.Children()) -{ - @Html.Partial("MyPartialName", child) -} -``` - -## Caching - -You don't normally need to cache the output of Partial views, like you don't normally need to cache the output of User Controls, but there are times when this is necessary. Like macro caching, we provide caching output of partial views. This is done by using an HtmlHelper extension method: - -```csharp -@await Html.CachedPartialAsync("ChildItem", page, TimeSpan.FromHours(1)) -``` - -The above will cache the output of your partial view for one hour when not running Umbraco in `debug` mode. Additionally, there are a few optional parameters you can specify to this method. Here is the full method signature: - -```csharp -Task CachedPartialAsync( - this IHtmlHelper htmlHelper, - string partialViewName, - object model, - TimeSpan cacheTimeout, - bool cacheByPage = false, - bool cacheByMember = false, - ViewDataDictionary? viewData = null, - Func? contextualKeyBuilder = null) -``` - -So you can specify to cache by member and/or by page and also specify additional view data to your partial view. \* _However_\*, if your view data is dynamic (meaning it could change per page request) the cached output will still be returned. This same principle applies if the model you are passing in is dynamic. Please be aware of this: if you have a different model or viewData for any page request, the result will be the cached result of the first execution. If this is not desired you can generate your own cache key to differentiate cache instances using the contextualKeyBuilder parameter - -To create multiple versions based on one or more viewData parameters you can do something like this: - -```csharp -@await Html.CachedPartialAsync("ChildItem", Model, TimeSpan.FromHours(1), true, false, new ViewDataDictionary(ViewData) -{ - { "year", Context.Request.Query["year"] } -}, (model, viewData) => viewData?["year"] + viewData?["Parameter2"]?.ToString() ) -``` - -Or using a custom helper function: - -```csharp -@functions{ - private static Func? CacheBy(params string[] keys) - { - return (model, viewData) => String.Join("", keys.Select(s => viewData?[s]?.ToString() ?? string.Empty)); - } -} - -@await Html.CachedPartialAsync("MediaGallery", Model, TimeSpan.FromHours(1), true, false, new ViewDataDictionary(ViewData) - { - { "year", Context.Request.Query["year"] } - }, CacheBy("year", "Parameter2")) -``` - -Or even based on a property on the Model (though if Model is the current page then `cacheByPage` should be used instead): - -```csharp - @await Html.CachedPartialAsync("MediaGallery", Model, TimeSpan.FromHours(1), true, false, new ViewDataDictionary(ViewData) { }, - (model, viewData) => (model is IPublishedContent pc ? pc.Name : null) ?? string.Empty) -``` - -Regardless of the complexity here the contextualKeyBuilder function needs to return a single string value. - -Caching is only enabled when your application has `debug="false"`. When `debug="true"` caching is disabled. Also, the cache of all CachedPartials is emptied on Umbraco publish events. diff --git a/10/umbraco-cms/reference/templating/mvc/querying.md b/10/umbraco-cms/reference/templating/mvc/querying.md deleted file mode 100644 index 01e03094eed..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/querying.md +++ /dev/null @@ -1,128 +0,0 @@ ---- - - ---- - - -# Querying & Traversal - -_This section will describe how you can render content from other nodes besides the current page in your MVC Views_ - -## Querying for content and media by id - -The easiest way to get some content by Id is to use the following syntax (where 1234 is the content id you'd like to query for): - -```csharp -// to return IPublishedContent -@Umbraco.Content(1234) -``` - -You can also query for multiple content items using multiple ids: - -```csharp -// to return the strongly typed (IEnumerable) collection -@Umbraco.Content(1234, 4321, 1111, 2222) -``` - -This syntax will support an unlimited number of Ids passed to the method. - -You can also retrieve content using the `Guid` Id. In the example "ca4249ed-2b23-4337-b522-63cabe5587d1" is the key of the content. - -```csharp -// to return the Umbraco.Core.Models.IPublishedContent -@Umbraco.Content(Guid.Parse("ca4249ed-2b23-4337-b522-63cabe5587d1")) -``` - -You can also pass a [Udi](../../querying/udi-identifiers.md) to retrieve the content. - -```csharp -// to return the Umbraco.Core.Models.IPublishedContent -@Umbraco.Content(Udi.Create("document", Guid.Parse("ca4249ed-2b23-4337-b522-63cabe5587d1"))) -``` -The same query structures apply to media: - -```csharp -@Umbraco.Media(9999) -@Umbraco.Media(9999,8888,7777) -@Umbraco.Media(9999) -@Umbraco.Media(9999,8888,7777) -@Umbraco.Content(Guid.Parse("ca4249ed-2b23-4337-b522-63cabe5587d1")) -@Umbraco.Content(Udi.Create("media", Guid.Parse("ca4249ed-2b23-4337-b522-63cabe5587d1"))) -``` - -## Traversing - -All of these extension methods are available on `Umbraco.Core.Models.IPublishedContent` so you can have strongly typed access to all of them with intellisense for both content and media. The following methods return `IEnumerable` - -```csharp -Children() // this is the same as using the Children property on the content item. -Ancestors() -Ancestors(int level) -Ancestors(string nodeTypeAlias) -AncestorsOrSelf() -AncestorsOrSelf(int level) -AncestorsOrSelf(string nodeTypeAlias) -Descendants() -Descendants(int level) -Descendants(string nodeTypeAlias) -DescendantsOrSelf() -DescendantsOrSelf(int level) -DescendantsOrSelf(string nodeTypeAlias) -Siblings() -SiblingsAndSelf() -``` - - -Additionally there are other methods that will return a single `IPublishedContent` - -```csharp -Ancestor() -AncestorOrSelf() -AncestorOrSelf(int level) -AncestorOrSelf(string nodeTypeAlias) -AncestorOrSelf(Func func) -``` - -## Complex querying (Where) - -With the `IPublishedContent` model we support strongly typed LINQ queries out of the box so you will have intellisense for that. - -### Some examples - -#### Where children are visible - -```csharp -@Model.Children.Where(x => x.IsVisible()) -``` - -#### Traverse for sitemap - -```csharp -var items = @Model.Children.Where(x => x.IsVisible() && x.Level <= 4) -``` -{% hint style="info" %} -The two examples below have not been verified for Umbraco 9 and 10 yet. - -therefore they might not work on the latest versions of Umbraco. -{% endhint %} - -#### Content sub menu - -```csharp -@Model.AncestorOrSelf(1).Children.Where(x => x.DocumentTypeAlias == "DatatypesFolder").First().Children -``` - -#### Complex query - -With the strongly typed `IPublishedContent` you can do complex queries. - -```csharp -// This example gets the top level ancestor for the current node, and then gets -// the first node found that contains "1173" in the array of comma delimited -// values found in a property called 'selectedNodes'. - -var result = @Model.Ancestors().OrderBy(x => x.Level) - .Single() - .Descendants() - .FirstOrDefault(x => x.GetPropertyValue("selectedNodes", "").Split(',').Contains("1173")); -``` diff --git a/10/umbraco-cms/reference/templating/mvc/viewcomponents.md b/10/umbraco-cms/reference/templating/mvc/viewcomponents.md deleted file mode 100644 index 445e80cb02b..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/viewcomponents.md +++ /dev/null @@ -1,106 +0,0 @@ ---- - - ---- - -# Using View Components in Umbraco - -In the previous versions of MVC, we used Child Actions to build reusable components/widgets consisting of both Razor markup and backend logic. The backend logic was implemented as a controller action and marked with a _\[ChildActionOnly]_ attribute. Child Actions are no longer supported in ASP.NET Core MVC. Instead, we will use the _View Component_ feature. - -## View Component Overview - -View components replace the traditional Controller (SurfaceController)/Partial View relationship and instead offers a modular approach of separating your views in to several smaller units. View Components are self-contained objects that consistently render HTML from a Razor view. - -View components are: - -* Generated from a C# class -* Derived from the base class ViewComponent and -* Associated with a Razor file (\*.cshtml) to generate markup. - -[View components](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-5.0) are similar to partial views but they are much more powerful compared to the partial views. View components do not use model binding, instead they work with the data provided when calling it. - -View Components can be implemented in any part of the web application where there are some possibilities to duplicate code like Header, Navigation Pane, Login Panel, Menu, Shopping Cart, Footer, BlockList Items and so on. View Components behave like a web part containing both business logic and UI design to create a package which can be reused in multiple parts of the web application. - -A view component code consists of two parts: - -* The View Component class derived from the `ViewComponent` class: - - ```csharp - [ViewComponent(Name = "Employee")] - public class EmployeeViewComponent : ViewComponent - {} - ``` -* Returns a Task object as `IViewComponentResult`: - - ```csharp - public IViewComponentResult Invoke() - { - return Content("Hi I'm an Employee Component"); - } - ``` - -### Create a class for a ViewComponent - -In this example, let's create a ViewComponent for a Product List and render it on the _HomePage_ of the website. - -Create a folder named **ProductView**. In this folder, create a new class named **ProductViewViewComponent.cs** as below: - -```csharp -using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; - -namespace Umbraco.Docs.Samples.Web.Components.ProductView -{ - public class ProductViewViewComponent : ViewComponent - { - public IViewComponentResult Invoke() - { - List products = new List() { - "Product 1", "Product 2", "Product 3", "Product 4", "Product 5" - }; - - return View(products); - } - } -} -``` - -### Create a View for ViewComponent - -In **Views** folder, create new folders at `Views\Shared\Components\ProductView`. In the **ProductView** folder, create a new file named **Default.cshtml** as below: - -```csharp -

Welcome to your Home Page

-

Products List

-
    - @foreach (var product in Model) - { -
  • @product
  • - } -
-``` - -#### UmbracoHelper in a ViewComponent - -Adding the following declaration will give access to the UmbracoHelper object inside the ViewComponent View - -```csharp -@inject Umbraco.Cms.Web.Common.UmbracoHelper Umbraco -``` - -### Invoking a View Component - -You can invoke a ViewComponent from anywhere (even from within a Controller or another ViewComponent). Since this is our Product List, we want it rendered on the Home page - so we’ll invoke it from our HomePage.cshtml file using: - -```csharp - @(await Component.InvokeAsync("ProductView")) -``` - -You can read about different ways of invoking your view component in the [View components in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-5.0#invoking-a-view-component) section of the Microsoft Documentation.view=aspnetcore-5.0) - -## View Component Locations - -By default, the framework searches for the Component View path in the following areas: - -* `/Views/{Controller Name Folder}/Components/{View Component Name Folder}/{View Name}` -* `/Views/Shared/Components/{View Component Name Folder}/{View Name}` diff --git a/10/umbraco-cms/reference/templating/mvc/views.md b/10/umbraco-cms/reference/templating/mvc/views.md deleted file mode 100644 index f189a41abc3..00000000000 --- a/10/umbraco-cms/reference/templating/mvc/views.md +++ /dev/null @@ -1,112 +0,0 @@ -# Working with MVC Views in Umbraco - -_Working with MVC Views and Razor syntax in Umbraco_ - -## Properties available in Views - -All Umbraco views inherit from `Umbraco.Cms.Web.Common.Views.UmbracoViewPage` along with the using statement `@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;`. This exposes many properties that are available in razor. The properties on the Document Type can be accessed in a number of ways: - -* @Model (of type `Umbraco.Web.Mvc.ContentModel`) -> the model for the view which contains the standard list of IPublishedContent properties but also gives you access to the typed current page (of type whatever type you have added in the angled brackets). -* @Umbraco (of type `UmbracoHelper`) -> contains many helpful methods, from rendering macros and fields to retrieving content based on an Id and tons of other helpful methods. [See UmbracoHelper Documentation](../../querying/umbracohelper.md) -* @Html (of type `HtmlHelper`) -> the same HtmlHelper you know and love from Microsoft but we've added a bunch of handy extension methods like @Html.BeginUmbracoForm -* @UmbracoContext (of type `Umbraco.Cms.Web.Common.UmbracoContext`) - -## Rendering a field in a strongly typed view - -This is probably the most used method which renders the contents of a field using the alias of the content item. - -```csharp -@Model.Value("bodyContent") -``` - -If you're using the method from within a partial view then be aware that you will need to inherit the context so the method knows which type to get the desired value from. You'd do this at the top of partial view and so strongly typed properties can then be accessed in the partial view. For instance you can pass "HomePage" like this: - -```csharp -@inherits UmbracoViewPage -... -@Model.Value("title") -``` - -You will also need to pass the "Context" to the @Model.Value() method if you're looping over a selection like this where we pass the "item" variable. - -Looping over a selection works in a similar way. If you have a property that contains, for instance, an IEnumberable collection, you can access the individual items using a foreach loop. Below illustrates how you might do that using "item" as a variable. - -```csharp -@{ - var collection = Model.ItemList; -} - -
    - @foreach(var item in collection) - { -

    @item.Name

    - } -
-``` - -If you want to convert a type and it's possible, you can do that by typing a variable and assigning the value from your property to it. This could look like the example below. - -```csharp -@foreach (TeamMember person in Model.TeamMembers) -{ - -

@person.Name

-
-} -``` - -In this example, we are looping through a list of items with the custom made type TeamMember assigned. This means we are able to access the strongly typed properties on the TeamMember item. - -## Rendering Macros - -Rendering a macro is done using UmbracoHelper. There are 3 overloads, we'll start with the most basic: - -This renders a macro with the specified alias without any parameters: - -```csharp -@await Umbraco.RenderMacroAsync("myMacroAlias") -``` - -This renders a macro with some parameters using an anonymous object: - -```csharp -@await Umbraco.RenderMacroAsync("myMacroAlias", new { name = "Ned", age = 28 }) -``` - -This renders a macro with some parameters using a dictionary - -```csharp -@await Umbraco.RenderMacroAsync("myMacroAlias", new Dictionary {{ "name", "Ned"}, { "age", 27}}) -``` - -[UmbracoHelper Documentation](../../querying/umbracohelper.md) - -## Accessing Member data - -`IMemberManager` is the gateway to everything related to members when templating your site. [IMemberManager Documentation](../../querying/imembermanager.md) - -```csharp -@using Umbraco.Cms.Core.Security; -@inject IMemberManager _memberManager; - -@if(_memberManager.IsLoggedIn()) -{ -

A Member is logged in

-} -else -{ -

No member is logged in

-} -``` - -## Models Builder - -Models Builder allows you to use strongly typed models in your views. Properties created on your document types can be accessed with this syntax: - -```csharp -@Model.BodyText -``` - -When Models Builder resolve your properties it will also try to use value converters to convert the values of your data into more convenient models. This allows you to access nested objects as strong types instead of having to rely on dynamics and risking having a lot of potential errors when working with these. - -[Models Builder documentation](../modelsbuilder/) diff --git a/10/umbraco-cms/reference/using-ioc.md b/10/umbraco-cms/reference/using-ioc.md deleted file mode 100644 index 2044a87ed70..00000000000 --- a/10/umbraco-cms/reference/using-ioc.md +++ /dev/null @@ -1,368 +0,0 @@ ---- -meta.Title: Umbraco Dependency Injection -description: Inversion of Control/Dependency Injection in Umbraco ---- - -# Inversion of Control / Dependency injection - -Umbraco v9+ supports dependency injection out of the box. Umbraco uses the [ASP.NET Core built-in dependency injection](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#service-lifetimes). This means that you don't have to install external packages to register and use your dependencies. If you're familiar with ASP.NET Core, the experience will be similar. - -`IUmbracoBuilder` is a Umbraco-specific abstraction on top of the `IServiceCollection`, its purpose is to aid in adding and replacing Umbraco-specific services, such as notification handlers, filesystems, server role accessor, and so on. You can access the `IServiceCollection` directly to add your custom services through the `Services` property, see below for a concrete example: - -```c# -IUmbracoBuilder.Services -``` - -## Registering dependencies - -There are two strategies for registering your own dependencies to the container, which one you should use depends on whether you're making a package, or making custom services for your own site. - -### Registering dependencies for your site - -When working with your site, and not a package, the recommended way to register dependencies is with the `ConfigureServices` method of the `Startup` class in `Startup.cs`: - -```c# -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - // If you need to add something Umbraco specific, do it in the "AddUmbraco" builder chain, using the IUmbracoBuilder extension methods. - .AddNotificationHandler() - .Build(); - - // Regular services can be added outside the "AddUmbraco" builder chain, using the default IServiceCollection. - services.AddSingleton(); -} -``` - -### Registering dependencies in packages - -When working with packages, you won't have access to the `Startup.cs` file, so instead you must use a [composer](../implementation/composing.md) to register your own dependencies in the container, using the `Services` property, or appropriate extension method, of the `IUmbracoBuilder`: - -```csharp -using IOCDocs.NotificationHandlers; -using IOCDocs.Services; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Notifications; - -namespace IOCDocs -{ - public class MyComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - builder.Services.AddSingleton(); - } - } -} -``` - -{% hint style="info" %} -Remember to add `Umbraco.Cms.Core.DependencyInjection` and `Microsoft.Extensions.DependencyInjection` as 'using' statements where you register your services, to gain access to the `IUmbracoBuilder`, its extension methods, and the Microsoft \`IServiceProvider. -{% endhint %} - -### Builder extension methods - -Depending on your scenario, you may have a lot of dependencies you need to register, in this case, your `Startup.cs` or Composer might become cluttered and hard to manage. A great way to manage multiple services is by creating your own custom extension methods for the `IUmbracoBuilder`, this way you can group similar dependencies in extension methods and register them all in as little as a single call: - -```c# -using IOCDocs.NotificationHandlers; -using IOCDocs.Services; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Notifications; - -namespace IOCDocs -{ - public static class MyCustomBuilderExtensions - { - public static IUmbracoBuilder RegisterCustomNotificationHandlers(this IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - {...} - return builder; - } - - public static IUmbracoBuilder RegisterCustomServices(this IUmbracoBuilder builder) - { - builder.Services.AddSingleton(); - {...} - return builder; - } - - public static IUmbracoBuilder AddCustomServices(this IUmbracoBuilder builder) - { - builder.RegisterCustomNotificationHandlers(); - builder.RegisterCustomServices(); - return builder; - } - } -} -``` - -{% hint style="info" %} -It is not required to have an interface for your dependency: - -```csharp -services.AddSingleton(); -``` -{% endhint %} - -Now you can call your `AddCustomServices` in either the `Startup.cs` file, or your composer like so: - -```c# -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - // Register all our custom services in one go. - .AddCustomServices() - .Build(); -} -``` - -```c# -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.DependencyInjection; - -namespace IOCDocs -{ - public class MyComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - // Register all our custom services in one go. - builder.AddCustomServices(); - } - } -} -``` - -### Service lifetime - -During registration you have to define the lifetime of your service: - -```csharp -IServiceCollection.AddTransient(); -IServiceCollection.AddScoped(); -IServiceCollection.AddSingleton(); -``` - -There is three possible lifetimes: - -* Transient - always creates a new instance - * A new instance will be created each time it's injected. -* Scoped - one unique instance per web request (connection) - * Scoped services are disposed at the end of the request - * Be very careful not to resolve a scoped service from a singleton, since it may cause it to have an incorrect state in subsequent requests. -* Singleton - one unique instance for the whole web application - * The single instance will be shared across all web requests. - -For more information, have a look at the official [Microsoft documentation](https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#service-lifetimes). - -## Injecting dependencies - -Once you have registered your services, factories, helpers or whatever you need for you application, you can go ahead and inject them where needed. - -### Injecting dependencies into a class - -If you need to inject your service into a controller, or another service, you'll do so through the class - -```csharp -using IOCDocs.Services; -using Umbraco.Cms.Web.Common.Controllers; - -namespace IOCDocs.Controllers -{ - public class FooController : UmbracoApiController - { - private readonly IFooBar _fooBar; - - public FooController(IFooBar fooBar) - { - _fooBar = fooBar; - } - - public string Foo() - { - var bar = _fooBar.Foo(); - return bar; - } - } -} -``` - -If you place a breakpoint on `var bar = _foobar.Foo()`, open `/Umbraco/Api/foo/foo` in your browser and inspect the variable, you'll see that the value is `bar`, which is what you'd expect since all the `Foobar.Foo()` method does it to return `Bar` as a string: - -```csharp -namespace IOCDocs.Services -{ - public class Foobar : IFooBar - { - public string Foo() => "Bar"; - } -} -``` - -### Injecting dependencies into a View or Template - -You might need to use services within your templates or views, fortunately, you can inject services directly into your views using the `@inject` keyword. You can for example inject the `Foobar` from above into a view like so: - -```html -@using Umbraco.Cms.Web.Common.PublishedModels; -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; - -@* Add a using for the namespace of the service *@ -@using IOCDocs.Services -@* Now you can inject it *@ -@inject IFooBar _fooBar - -@{ - Layout = null; -} - -

@_fooBar.Foo()

-``` - -If you then load the page which uses this template you'll see a heading with "Bar", which we got from our service. - -Note that in order to use our service we also have to add a using statement for the namespace of the service. - -## Other things you can inject - -Most of (if not all) the Umbraco goodies you work with every day can be injected. Here are some examples. - -### UmbracoHelper - -[Read more about the UmbracoHelper](querying/umbracohelper.md) - -`UmbracoHelper` is a scoped service, therefore you can only use it in services that are also scoped, or transient. To get UmbracoHelper you must inject `IUmbracoHelperAccessor` and use that to resolve it: - -```csharp -using System.Collections.Generic; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Web.Common; - -namespace IOCDocs.Services -{ - // This service must be scoped - public class MyCustomScopedService - { - private readonly IUmbracoHelperAccessor _umbracoHelperAccessor; - - public MyCustomScopedService(IUmbracoHelperAccessor umbracoHelperAccessor) - { - _umbracoHelperAccessor = umbracoHelperAccessor; - } - - public IEnumerable GetContentAtRoot() - { - // Try and get the Umbraco helper - var success = _umbracoHelperAccessor.TryGetUmbracoHelper(out var umbracoHelper); - if (success is false) - { - // Failed to get UmbracoHelper, probably because it was accessed outside of a scoped/transient service. - return null; - } - - // We got Umbraco helper, now we can do something with it. - return umbracoHelper.ContentAtRoot(); - } - } -} -``` - -{% hint style="info" %} -The use of the UmbracoHelper is only possible when there's an instance of the UmbracoContext. [You can read more here](../implementation/services/). -{% endhint %} - -### ExamineManager - -[Read more about examine](searching/examine/). - -```csharp -using System; -using System.Collections.Generic; -using Examine; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Examine; -using Umbraco.Extensions; - -namespace IOCDocs.Services -{ - // This service must be scoped. - public class SearchService : ISearchService - { - private readonly IExamineManager _examineManager; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - - public SearchService(IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor) - { - _examineManager = examineManager; - _umbracoContextAccessor = umbracoContextAccessor; - } - - public IEnumerable Search(string searchTerm) - { - if (_examineManager.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out var index) is false) - { - throw new InvalidOperationException($"No index found by name {Constants.UmbracoIndexes.ExternalIndexName}"); - } - - if (!(index is IUmbracoIndex umbracoIndex)) - { - throw new InvalidOperationException("Could not cast"); - } - - // Do stuff with the index - if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext) is false) - { - throw new InvalidOperationException("Could not get Umbraco context"); - } - - return umbracoIndex.Searcher.Search(searchTerm).ToPublishedSearchResults(umbracoContext.PublishedSnapshot.Content); - } - } -} -``` - -### ILogger - -[Read more about logging](../fundamentals/code/debugging/logging.md) - -```csharp -using System; -using Microsoft.Extensions.Logging; - -namespace IOCDocs.Services -{ - public class Foobar : IFooBar - { - private readonly ILogger _logger; - - public Foobar(ILogger logger) - { - _logger = logger; - } - - public void Foo() - { - _logger.LogInformation("Method Foo called at {DateTime}", DateTime.UtcNow); - } - } -} -``` - -## Using DI in Services and Helpers - -[Services and Helpers](../implementation/services/) - For more examples of using DI and gaining access to Services and Helpers, and creating your own custom Services and Helpers to inject. diff --git a/10/umbraco-cms/tutorials/add-google-authentication.md b/10/umbraco-cms/tutorials/add-google-authentication.md deleted file mode 100644 index c256b9fb36d..00000000000 --- a/10/umbraco-cms/tutorials/add-google-authentication.md +++ /dev/null @@ -1,335 +0,0 @@ ---- -description: >- - A tutorial on setting up Google authentication for the Umbraco CMS backoffice - users. ---- - -# Add Google Authentication - -The Umbraco Backoffice supports external login providers (OAuth) for performing authentication of your users. This could be any OpenIDConnect provider such as Entra ID/Azure Active Directory, Identity Server, Google, or Facebook. - -In this tutorial, we will take you through the steps of setting up a Google login for the Umbraco CMS backoffice. - -## What is a Google Login? - -When you log in to the Umbraco Backoffice, you need to enter your username and password. Integrating your website with Google authentication adds a button that you can click to log in with your Google account. - -![Google login screen](images/googleLoginScreen_v13.png) - -## Why? - -I'm sure a lot of content editors and implementors of your Umbraco sites would love to have one less password to remember. Click **Sign in with Google** and if you are already logged in with your Google account, it will log you in directly. - -### What the tutorial covers - -1. [Setting up a Google OAuth API](add-google-authentication.md#id-1.-setting-up-a-google-oauth-api) -2. [Integrating Google Auth in your project](add-google-authentication.md#id-2.-integrating-google-auth-in-your-project) -3. [Configuring the solution to allow Google logins](add-google-authentication.md#id-3.-configuring-the-solution-to-allow-google-logins) - -### Prerequisites - -For this tutorial, you need: - -* [Visual Studio](https://visualstudio.microsoft.com/) installed. -* A [Google](https://myaccount.google.com/) account. -* A working [Umbraco solution](https://umbraco.com/products/umbraco-cloud/). - -## 1. Setting up a Google OAuth API - -The first thing to do is set up a Google API. To do this, you need to go to [https://console.developers.google.com/](https://console.developers.google.com/) and log in with your Google account. - -### Setup a Google Console Project - -1. Click the project dropdown and select **New Project**. - - ![Project dropdown list](images/Project_dropdown_list_v13.png) -2. Enter a **Project name**, **Organization**, and **Location**. -3. Click **Create**. - -### Enable the Google+ API - -1. Open the newly created project from the project dropdown. -2. Click **Enable APIs and Services**. - - ![Enable APIs](images/Enable_Apis_v13.png) -3. Type **Google+ API** in the **Search** field. -4. Select it and then **Enable** it. - - ![Enable Google APIs](images/Enable_Google_API_v13.png) - -### Set up an OAuth Consent Screen - -Before you can create the credentials, you need to configure your consent screen. - -1. Click **OAuth consent screen** from the left-side navigation menu. -2. Choose the **User Type** that fits your setup. -3. Click **Create**. - - ![Select User Type](images/User_Type_v13.png) -4. Fill in the required information: - * App name - * User support email - * Developer contact information -5. Click **Save and Continue**. -6. Select the scopes your project needs. -7. Click **Save and Continue**. -8. Verify the details you have provided. -9. Click **Back to Dashboard** to complete creating the Consent screen. - -### Create credentials - -1. Click **Credentials** from the left-side navigation menu. -2. Click **Create Credentials**. -3. Select **OAuth Client ID** from the dropdown. - - ![Select OAuth Client ID](images/OAuth_Client_Id_v13.png) -4. Select **Web Application** from the **Application type** dropdown. -5. Enter the following details: - - * Application **Name** - * **Authorized JavaScript origins** - * **Authorized redirect URIs** - - ![Credentials](images/credentials_v13.png) -6. Click **Create**. - -A popup appears displaying the **Client Id** and **Client Secret**. You will need these values later while configuring your solution. - -{% hint style="info" %} -The **Client Id** and **Client Secret** can always be accessed from the **Credentials** tab in the **APIs & Services** menu. -{% endhint %} - -## 2. Integrating Google Auth in your project - -Once the Google API is set up it is time to install the Google Auth provider on the Umbraco project. - -If you are working with a Cloud project, see the [Working locally](https://docs.umbraco.com/umbraco-cloud/set-up/working-locally) article to complete this step. - -### Installing a Nuget Package - -You can install and manage packages in a project. - -1. Navigate to your project/solution folder. - -{% hint style="info" %} -If you have cloned down an Umbraco Project, navigate to the `src` folder where you can see a `.csproj` file. -{% endhint %} - -2. Open a command-line of your choice such as "Command Prompt" at the mentioned location. -3. Run the following command to install the `Microsoft.AspNetCore.Authentication.Google` package. - - ```cli - dotnet add package Microsoft.AspNetCore.Authentication.Google - ``` -4. Once the package is installed, open the **.csproj** file to ensure if the package reference is added: - - ```js - - - - ``` - -{% hint style="info" %} -You can check the [latest version of the package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Google) before installing it. -{% endhint %} - -For more information on installing and using a package with the .Net CLI, see [Microsoft Documentation](https://learn.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-using-the-dotnet-cli). - -## 3. Configuring the solution to allow Google logins - -To use an external login provider such as Google on your Umbraco CMS project, you have to implement a couple of new classes: - -* A custom-named configuration class. -* A static extension class. - -You can create these files in a location of your choice. In this tutorial, the files will be added to an `ExternalUserLogin/GoogleAuthentication` folder. - -1. Create a new class:`GoogleBackOfficeExternalLoginProviderOptions.cs`. -2. Add the following code to the file: - -{% code title="GoogleBackOfficeExternalLoginProviderOptions.cs" lineNumbers="true" %} -```csharp -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Web.BackOffice.Security; - -namespace MyCustomUmbracoProject.ExternalUserLogin.GoogleAuthentication; - -public class GoogleBackOfficeExternalLoginProviderOptions : IConfigureNamedOptions -{ - public const string SchemeName = "OpenIdConnect"; - public void Configure(string? name, BackOfficeExternalLoginProviderOptions options) - { - ArgumentNullException.ThrowIfNull(name); - - if (name != Constants.Security.BackOfficeExternalAuthenticationTypePrefix + SchemeName) - { - return; - } - - Configure(options); - } - - public void Configure(BackOfficeExternalLoginProviderOptions options) - { - // Customize the login button - options.ButtonStyle = "btn-danger"; - options.Icon = "icon-cloud"; - - // The following options are only relevant if you - // want to configure auto-linking on the authentication. - options.AutoLinkOptions = new ExternalSignInAutoLinkOptions( - - // Set to true to enable auto-linking - autoLinkExternalAccount: true, - - // [OPTIONAL] - // Default: "Editor" - // Specify User Group. - defaultUserGroups: new[] { Constants.Security.EditorGroupAlias }, - - // [OPTIONAL] - // Default: The culture specified in appsettings.json. - // Specify the default culture to create the User as. - // It can be dynamically assigned in the OnAutoLinking callback. - defaultCulture: null, - - // [OPTIONAL] - // Enable the ability to link/unlink manually from within - // the Umbraco backoffice. - // Set this to false if you don't want the user to unlink - // from this external login provider. - allowManualLinking: true - ) - { - // [OPTIONAL] Callback - OnAutoLinking = (autoLinkUser, loginInfo) => - { - // Customize the user before it's linked. - // Modify the User's groups based on the Claims returned - // in the external ogin info. - }, - OnExternalLogin = (user, loginInfo) => - { - // Customize the User before it is saved whenever they have - // logged in with the external provider. - // Sync the Users name based on the Claims returned - // in the external login info - - // Returns a boolean indicating if sign-in should continue or not. - return true; - } - }; - - // [OPTIONAL] - // Disable the ability for users to login with a username/password. - // If set to true, it will disable username/password login - // even if there are other external login providers installed. - options.DenyLocalLogin = false; - - // [OPTIONAL] - // Choose to automatically redirect to the external login provider - // effectively removing the login button. - options.AutoRedirectLoginToExternalProvider = false; - } -} -``` -{% endcode %} - -{% hint style="info" %} -The code used here, enables [auto-linking](../reference/security/external-login-providers.md#auto-linking) with the external login provider. This enables the option for users to login to the Umbraco backoffice prior to having a backoffice User. - -Set the `autoLinkExternalAccount` to `false` in order to disable auto-linking in your implementation. -{% endhint %} - -3. Create a new class: `GoogleAuthenticationExtensions.cs`. -4. Add the following code to the file: - -{% code title="GoogleAuthenticationExtensions.cs" lineNumbers="true" %} -```csharp -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Extensions; -using Microsoft.Extensions.DependencyInjection; - -namespace MyCustomUmbracoProject.ExternalUserLogin.GoogleAuthentication; - -public static class GoogleAuthenticationExtensions -{ - public static IUmbracoBuilder AddGoogleAuthentication(this IUmbracoBuilder builder) - { - // Register ProviderBackOfficeExternalLoginProviderOptions here rather than require it in startup - builder.Services.ConfigureOptions(); - - builder.AddBackOfficeExternalLogins(logins => - { - logins.AddBackOfficeLogin( - backOfficeAuthenticationBuilder => - { - - // The scheme must be set with this method to work for the back office - var schemeName = backOfficeAuthenticationBuilder.SchemeForBackOffice(GoogleBackOfficeExternalLoginProviderOptions.SchemeName); - - ArgumentNullException.ThrowIfNull(schemeName); - - backOfficeAuthenticationBuilder.AddGoogle( - schemeName, - options => - { - // Callback path: Represents the URL to which the browser should be redirected to. - // The default value is '/signin-google'. - // The value here should match what you have configured in you external login provider. - // The value needs to be unique. - options.CallbackPath = "/umbraco-google-signin"; - options.ClientId = "YOURCLIENTID"; // Replace with your client id generated while creating OAuth client ID - options.ClientSecret = "YOURCLIENTSECRET"; // Replace with your client secret generated while creating OAuth client ID - }); - }); - }); - return builder; - } -} -``` -{% endcode %} - -5. Replace **YOURCLIENTID** and **YOURCLIENTSECRET** with the values from the **OAuth Client Ids Credentials** window. -6. Update `ConfigureServices` in your `Startup.cs` class to register your configuration with Umbraco. - -{% code title="Startup.cs" lineNumbers="true" %} -```csharp -using MyCustomUmbracoProject.ExternalUserLogin.GoogleAuthentication; - -public void ConfigureServices(IServiceCollection services) -{ - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - - // Register your new static extension class - .AddGoogleAuthentication() - - .Build(); -} -``` -{% endcode %} - -7. Build and run the website. -8. Log in to the backoffice using the Google Authentication option. - -{% hint style="info" %} -If auto-linking is disabled, the user will need to follow these steps in order to be able to use the Google Authentication: - -1. Login to the backoffice using Umbraco credentials. -2. Select your user profile in the top-right corner. -3. Click **Link your Google account** under External login providers. -4. Choose the account you wish to link. - -For future backoffice logins, the user will be able to use Google Authentication to login. -{% endhint %} - -![Google login screen](images/googleLoginScreen_v13.png) - -## Related Links - -* [External login providers](../reference/security/external-login-providers.md) -* [Linking External Login Provider accounts](../reference/security/external-login-providers.md#auto-linking) diff --git a/10/umbraco-cms/tutorials/add-microsoft-entra-id-authentication.md b/10/umbraco-cms/tutorials/add-microsoft-entra-id-authentication.md deleted file mode 100644 index 02b1924c5bb..00000000000 --- a/10/umbraco-cms/tutorials/add-microsoft-entra-id-authentication.md +++ /dev/null @@ -1,217 +0,0 @@ ---- -description: >- - Learn how to use Microsoft Entra ID (Azure Active Directory) credentials to login to Umbraco as a member. ---- - -# Authenticating the Umbraco backoffice with Microsoft Entra ID (Azure Active Directory) credentials - -This article describes how to configure Microsoft Entra ID (Azure Active Directory/Azure AD) with Umbraco Users and Members. - -## Configuring Entra ID - -Before your applications can interact with Entra ID B2C, they must be registered in a tenant that you manage. For more information, see [Microsoft's Tutorial: Create an Azure Active Directory B2C tenant](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant). - -## Installing the NuGet Package - -You need to install the `Microsoft.AspNetCore.Authentication.MicrosoftAccount` NuGet package. There are two approaches to installing the packages: - -1. Use your favorite IDE and open up the **NuGet Package Manager** to search and install the packages. -2. Use the command line to install the package. - -## Entra ID Authentication for Users - -1. Create a class called `BackofficeAuthenticationExtensions.cs` to configure the external login. - - ```csharp - using Microsoft.AspNetCore.Authentication.MicrosoftAccount; - using Microsoft.Extensions.DependencyInjection; - - namespace MyApp - { - public static class BackofficeAuthenticationExtensions - { - public static IUmbracoBuilder ConfigureAuthentication(this IUmbracoBuilder builder) - { - builder.AddBackOfficeExternalLogins(logins => - { - const string schema = MicrosoftAccountDefaults.AuthenticationScheme; - - logins.AddBackOfficeLogin( - backOfficeAuthenticationBuilder => - { - backOfficeAuthenticationBuilder.AddMicrosoftAccount( - // the scheme must be set with this method to work for the back office - backOfficeAuthenticationBuilder.SchemeForBackOffice(schema) ?? string.Empty, - options => - { - //By default this is '/signin-microsoft' but it needs to be changed to this - options.CallbackPath = "/umbraco-signin-microsoft/"; - //Obtained from the ENTRA ID B2C WEB APP - options.ClientId = "{your_client_id}"; - //Obtained from the ENTRA ID B2C WEB APP - options.ClientSecret = "{your_client_secret}"; - //options.TokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"; - //options.AuthorizationEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize"; - }); - }); - }); - return builder; - } - } - } - ``` - - {% hint style="info" %} - Ensure to replace **{your\_client\_id}** and **{your\_client\_secret}** in the code with the values from the Entra ID tenant. If Entra ID is configured to use accounts in the organizational directory only (single tenant), you also have to specify the Token and AuthorizationEndpoint. - {% endhint %} -2. Update `ConfigureServices` method in the `Startup.cs` file: - - ```csharp - public void ConfigureServices(IServiceCollection services) - { - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - // Add ConfigureAuthentication - .ConfigureAuthentication() - .Build(); - } - ``` -3. Build and run the website. You can now login with your Entra ID credentials. - - ![AD Login Screen](../reference/security/images/AD_Login.png) - -## Entra ID Authentication for Members - -1. Create a Member login functionality, see the [Member registration and login](../../tutorials/members-registration-and-login.md#member-registration-and-login) article. -2. Create a class called `MemberAuthenticationExtensions.cs` to configure the external login. - - ```csharp - using Microsoft.Extensions.DependencyInjection; - - namespace MyApp - { - public static class MemberAuthenticationExtensions - { - public static IUmbracoBuilder ConfigureAuthenticationMembers(this IUmbracoBuilder builder) - { - builder.Services.ConfigureOptions(); - builder.AddMemberExternalLogins(logins => - { - logins.AddMemberLogin( - membersAuthenticationBuilder => - { - membersAuthenticationBuilder.AddMicrosoftAccount( - // The scheme must be set with this method to work for members - membersAuthenticationBuilder.SchemeForMembers(EntraIDB2CMembersExternalLoginProviderOptions.SchemeName), - options => - { - //Callbackpath - Important! The CallbackPath represents the URL to which the browser should be redirected to and the default value is - // /signin-oidc This should be unique!. - options.CallbackPath = "/umbraco-b2c-members-signin"; - //Obtained from the ENTRA ID B2C WEB APP - options.ClientId = "YOURCLIENTID"; - //Obtained from the ENTRA ID B2C WEB APP - options.ClientSecret = "YOURCLIENTSECRET"; - options.SaveTokens = true; - }); - }); - }); - return builder; - } - } - } - ``` - -{% hint style="info" %} -``` -Ensure to replace **{your_client_id}** and **{your_client_secret}** in the code with the values from the Entra ID tenant. -``` -{% endhint %} - -1. To enable a member to link their account to an external login provider such as Entra ID in the Umbraco Backoffice, you have to implement a custom named configuration `MemberExternalLoginProviderOptions` for Members. Add the following code in the `EntraIDB2CMembersExternalLoginProviderOptions.cs` file: - - ```csharp - using Microsoft.Extensions.Options; - using Umbraco.Cms.Core; - using Umbraco.Cms.Web.Common.Security; - - namespace MyApp - { - public class EntraIDB2CMembersExternalLoginProviderOptions : IConfigureNamedOptions - { - public const string SchemeName = "EntraIDB2C"; - public void Configure(string name, MemberExternalLoginProviderOptions options) - { - if (name != "Umbraco." + SchemeName) - { - return; - } - - Configure(options); - } - - public void Configure(MemberExternalLoginProviderOptions options) - { - - options.AutoLinkOptions = new MemberExternalSignInAutoLinkOptions( - // must be true for auto-linking to be enabled - autoLinkExternalAccount: true, - - // Optionally specify the default culture to create - // the user as. If null it will use the default - // culture defined in the web.config, or it can - // be dynamically assigned in the OnAutoLinking - // callback. - - defaultCulture: null, - - // Optionally specify the default "IsApprove" status. Must be true for auto-linking. - defaultIsApproved: true, - - // Optionally specify the member type alias. Default is "Member" - defaultMemberTypeAlias: "Member" - - ) - { - // Optional callback - OnAutoLinking = (autoLinkUser, loginInfo) => - { - // You can customize the user before it's linked. - // i.e. Modify the user's groups based on the Claims returned - // in the externalLogin info - }, - OnExternalLogin = (user, loginInfo) => - { - // You can customize the user before it's saved whenever they have - // logged in with the external provider. - // i.e. Sync the user's name based on the Claims returned - // in the externalLogin info - - return true; //returns a boolean indicating if sign-in should continue or not. - } - }; - } - } - } - ``` -2. Next, update `ConfigureServices` method in the `Startup.cs` file: - - ```csharp - public void ConfigureServices(IServiceCollection services) - { - services.AddUmbraco(_env, _config) - .AddBackOffice() - .AddWebsite() - .AddComposers() - // Add ConfigureAuthentication - .ConfigureAuthentication() - //Add Members ConfigureAuthentication - .ConfigureAuthenticationMembers() - .Build(); - } - ``` -3. Build and run the website. Your members can now login with their Entra ID credentials. - - ![Entra ID Login Screen](../reference/security/images/AD_Login_Members.png) diff --git a/10/umbraco-cms/tutorials/connecting-umbraco-forms-and-zapier.md b/10/umbraco-cms/tutorials/connecting-umbraco-forms-and-zapier.md deleted file mode 100644 index dab45ec4803..00000000000 --- a/10/umbraco-cms/tutorials/connecting-umbraco-forms-and-zapier.md +++ /dev/null @@ -1,154 +0,0 @@ -# Connecting Umbraco Forms and Zapier - -This guide takes you through the steps of connecting your Umbraco Forms to Zapier. - -## What is Zapier - -[Zapier](https://zapier.com/) is an “if this, then that” tool that allows you to automate workflows between the different web apps you use. Zapier has integrations to more than 2,000 web apps and lets you connect to your accounts with a few clicks without any code. - -## Why use Zapier for your Umbraco Forms data - -Umbraco Forms stores entries in the backoffice. It has a set of default workflow types that you can use when a new form entry is submitted. To use this data in other applications, such as your Customer Relationship Management (CRM) or marketing automation platform, you need integrations to those platforms. Integration with Zapier can be done using the default workflows in Umbraco Forms. All without having to write any additional code. - -This enables marketers and editors to make automated workflows that pass data between the web apps they use without having to involve a developer. - -## Who is this tutorial for - -This tutorial is for all users of Umbraco and does not require any particular skills to be performed. It is especially useful for marketers who get the freedom to make integrations and automate tasks in a simpler and faster way. - -## Prerequisites - -Here is what you will need for this tutorial: - -* A paid Zapier account (Premium apps are unavailable in the free plan) -* Umbraco Forms -* A Google account (only necessary if you want to follow the last example in the guide) - -## Creating a Zapier webhook trigger - -The first step is to generate the webhook URL that your Umbraco Forms has to send data to. This is done by logging into your Zapier account and clicking “Make a Zap” - -![Zapier make a zap](images/zapierMakeZap.png) - -The next thing to do is pick an app in the “When this happens…” box. This is your trigger and determines when your Zap will start. Select the “Webhooks by Zapier” app - -![Zapier find webhooks trigger](images/zapierFindWebhooksTrigger.png) - -Now select the “Catch Hook” trigger event and click continue. - -![Zapier webhooks catch hook](images/zapierWebhooksCatchHook.png) - -Now you will get a “Custom Webhook URL” that you will need for your Umbraco Forms. - -![Zapier custom webhook URL](images/zapierCustomWebhookURL.png) - -Copy this URL and have it ready for later. You will need it when you set up your Umbraco Forms workflow. Now we have to go into the Umbraco backoffice, but keep the Zap you created open. We will get back to it later to finish setup. - -## Creating your Umbraco form - -Now it’s time to login to the Umbraco backoffice so you can create your form. If you already have a form you want to connect you can skip to the next step. - -To create a form you can follow this tutorial with step-by-step instructions: [Creating a form in Umbraco Forms](https://docs.umbraco.com/umbraco-forms/editor/creating-a-form). - -Once you have created your form you are ready to set up the workflow. - -## Setting up the “Send form to URL” workflow - -Once you have set up your form, it is time to add the “Send form to URL” workflow to your form. This will allow you to post your data to the Zapier webhook URL you generated earlier. - -Go to your form in the backoffice and click on “configure workflow”. In the “On Submit” workflow you click “Add workflow”. - -![Umbraco Forms Add Workflow](images/umbracoFormsAddWorkflow.png) - -Now choose the workflow “Send form to URL”. - -![Umbraco Forms Send form to URL workflow](images/umbracoFormsSendFormToURLWorkflow.png) - -After giving the workflow a descriptive name, you paste in the webhook URL from Zapier in the “Url” field and choose POST in “Method”. Leave “Fields”, “User” and “Password” blank. - -![Umbraco Forms Send form to URL webhook](images/umbracoFormsSendFormToURLWebhook.png) - -Now your workflow is ready. Submit your changes and save your form. - -## Submit an entry to the form - -Now your form is ready to send data to Zapier and any entry submitted will be posted to the Zapier webhook URL. - -To set up field mapping and actions in Zapier your form needs an entry. If this is a new form, add it to a page and submit an entry ([guide to adding your form to a page](https://docs.umbraco.com/umbraco-forms/editor/creating-a-form#adding-the-form-to-the-umbraco-site)). - -Here is the form and the fields that were submitted for this tutorial. - -![Umbraco Forms Fields Submitted](images/umbracoFormsFieldsSubmitted.png) - -Once you have an entry in your form you are done in the Umbraco backoffice. Now it is time to go back to Zapier and finish setting up your automation. - -## Find your form entry data in Zapier - -In Zapier, open up the Zap you started setting up in the first step of this guide. In that Zap we are now ready to continue the setup of our webhook trigger. Start by clicking continue and get to the “Find Data” step. - -![Zapier Find Webhook Data](images/zapierFindWebhookData.png) - -Now click on “Test trigger”. If there is an entry to the form it should look like this. - -![Zapier Webhook Data Found](images/zapierWebhookDataFound.png) - -Now you have data to further map in your Zap and can continue choosing the action for the Zap. If Zapier does not find any data, try to submit a new form entry. - -After clicking “continue” you are now starting on the “Do this…” action of your Zap. - -## Choose an action for your Zap - -Up until now, the steps will be the same for everyone. Now that you have connected Umbraco Forms and Zapier it is up to you to decide where you want to send the data. - -In this tutorial you will get an example of how you can send your data to Google Sheets. This allows you to see how a finalized Zap looks like. - -## Example: Sending data to Google Sheets - -As a “Do this…” action you want to send data to Google Sheets. Before doing so in your Zap you need to ensure that you have created a Google Sheet to receive the data. You also need to connect your Zapier account to your Google Sheets account. - -Once you have done these steps it is time to finish the setup of the Zap. - -First thing to do is find the “Google Sheets” app in the “Do this…” action. - -![Zapier Google Sheets App](images/zapierGoogleSheetsApp.png) - -Now choose the Action event “Create a spreadsheet row” and continue. - -![Zapier Google Sheets Action Event](images/zapierGoogleSheetsActionEvent.png) - -Now you need to choose the Google Sheets account you want to connect to. If you have not set this up yet, you will be prompted to do so. Once connected you choose that account and click continue. - -![Zapier Google Sheets Account](images/zapierGoogleSheetsAccount.png) - -Now you can choose which Google Drive to use, find the spreadsheet and choose the worksheet that you want to send the data to. After doing so, you will get a list of possible fields that you can post your data to. - -![Zapier Google Sheets Possible Fields](images/zapierGoogleSheetsPossibleFields.png) - -The fields showing are all columns in your spreadsheet that have a name in row 1. To map the input data to the different fields in the spreadsheet follow these steps: - -* Select the “Type or insert…” field. -* Choose which data to put in the field. - -![Zapier Google Sheets Webhook Data](images/zapierGoogleSheetsWebhookData.png) - -The data that was caught by the webhook will all be dynamic and you will want to pick the fields here. That way, when a new entry comes in, the field will dynamically insert the data they submitted for that field. - -![Zapier Google Sheets Data Mapped](images/zapierGoogleSheetsDataMapped.png) - -Once you have mapped all of the fields it is time to click “continue” and test if the data is sent correctly to our spreadsheet. - -![Zapier Google Sheets Test](images/zapierGoogleSheetsTest.png) - -Click “Test & Continue” and wait for it to process. Once it is done, go to the spreadsheet you created and see if the data is there. - -![Google Sheets Data](images/googleSheetsData.png) - -Tada! Now your Zap is ready and can be activated to automatically add form entries to Google Sheets. To activate the Zap you go back to your Zap and change the toggle from “Off” to “On”. Now it will be waiting for new form entries and be ready to send them to Google Sheets. - -## Connecting multiple Umbraco Forms to Zapier - -If you want to connect multiple forms to Zapier you can follow the above steps to do so. Remember to add individual Zaps to each form if the data being sent is different or you want to use different actions for the data. - -You can reuse the same Zap and webhook URL if all data sent to Zapier is formatted in the same way. Otherwise errors will occur. - -That’s it. Now you are ready to connect Umbraco Forms to Zapier and can use it to send data to the tools you choose. diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/README.md b/10/umbraco-cms/tutorials/creating-a-basic-website/README.md deleted file mode 100644 index fee5e868679..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/README.md +++ /dev/null @@ -1,62 +0,0 @@ ---- - - -product: "CMS" -meta.Title: "Creating a Basic Website using Umbraco" -description: "A guide to creating a Basic Website using Umbraco" ---- -# Creating a Basic Website using Umbraco - -_This tutorial was last tested on **Umbraco 10.0.0+**_ - -## Introduction - -This tutorial will take you step by step through an Umbraco website build. It will allow you to take any website "template" (e.g. flat HTML, CSS, and JavaScript) and install it into a fresh Umbraco site and wire up the sections that need content managing by Umbraco. - -We will avoid using any starter kits in this tutorial. Although these are extremely useful, they won’t provide you with an understanding of the basics of Umbraco, such as Document Types and Templates and how these work together to build pages. - -It is recommended that you work through the subsections in the following order. - -## [Getting Started](getting-started.md) - -To follow this tutorial please work through this section first. - -## [Creating Your First Document Type](document-types.md) - -How to create Document Types and what they do. - -## [Creating Your First Template and Content Node](creating-your-first-template-and-content-node.md) - -How to create your first template and create a content node. - -## [CSS & Images](css-and-images.md) - -Adding the CSS and JavaScript for your site into Umbraco. - -## [Displaying the Document Type Properties](displaying-the-document-type-properties.md) - -How to wire the Document Type Properties (Umbraco Data Fields) into the templates to output the editor's data in the right place. - -## [Creating a Master Template Part 1](creating-master-template-part-1.md) - -How to create a Master Template and use this to create more pages whilst minimising duplicate HTML code from your flat source files. - -## [Creating a Master Template Part 2](creating-master-template-part-2.md) - -Part 2 - using the Master template to create new page types. - -## [Setting The Navigation Menu](setting-the-navigation-menu.md) - -A solution for the template in the menu. - -## [Articles Parent and Article Items](article-parent-and-article-items.md) - -How to have a parent page that lists and links to child nodes automatically (e.g. an article list page containing a flexible/infinite number of articles - useful for Blogs or News pages). - -## [Adding Language Variants](adding-language-variants.md) - -At this point we have a basic site, but wouldn't it be cool if we could make the same site in another language? Read on to see how to get started with Language Variants! - -## [Conclusions and Where Next?](conclusion.md) - -By this point you'll have a basic working site - but where to next? You've barely scratched the surface of the power of Umbraco - a few links to send you on your way! diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/adding-language-variants.md b/10/umbraco-cms/tutorials/creating-a-basic-website/adding-language-variants.md deleted file mode 100644 index 580c16647d7..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/adding-language-variants.md +++ /dev/null @@ -1,88 +0,0 @@ -# Adding Language Variants - -Now that we have a basic site set up, let's make the site multilingual by making variations of our content in one more language. For this tutorial, we will make a Danish version of the `HomePage` page. - -## Adding a new language - -To add a new language, follow these steps: - -1. Go to the **Settings** tab. -2. Go to **Languages** in the **Settings** tree. The **Languages** window opens in the editor. -3. Click **Add Language**. The **Add Language** window opens in the editor. -4. Select a **Language** from the dropdown list. In this tutorial, we will pick Danish. - - ![Adding the Danish language](images/adding-danish-language.png) -5. In **Settings**, to set the new language as the: - * Default language for your site, toggle **Default Language**. - * Mandatory language for your site, toggle **Mandatory Language**. -6. Select a **Fallback Language** from the drop-down list. - - ![Adding a Fallback language](images/fallback-language.png) -7. Click **Save**. - -## Enabling Language Variants on Document Types and Properties - -To enable language variants on Document Types, follow these steps: - -1. Go to the **Settings** tab. -2. Select **HomePage** from the **Document Types** folder. -3. Go to the **Permissions** tab and toggle **Allow vary by culture** -4. Click **Save**. -5. Go to the **Design** tab. -6. Click on the gear icon ⚙ of the **Page Title** and toggle **Allow vary by culture**. -7. Click **Submit**. - - ![Allow property editor Language Variants](images/allow-varying-property-editor.png) -8. For this tutorial, we will not make any changes to the **Body Text**. Click **Save**. - -## Adding Culture and Hostnames to the root node of the website - -To add culture and hostnames, follow these steps: - -1. Go to the **Content** tab. -2. Right-click on the **...** dots next to the **Home Page** content node and select **Allow access to assign culture and hostnames**. - * In Umbraco 9 this menu is called **Culture and Hostnames**. -3. Add a domain for each hostname, like it's done here: - - ![Culture and Hostnames](images/culture-and-hostnames.png) -4. Click **Save**. - -## Adding Language Variants to the Content - -You will find a language dropdown above your content tree. If it's not there, you might need to refresh the page: - -![Language of Content Tree](images/language-content-tree.png) - -In the language dropdown, you will find all the languages that you have installed for your site. You can switch between them to update the content variations for each language. - -To add language variants to the content, follow these steps: - -1. Go to the **Home Page** node. You will find a language dropdown next to the title at the top: - - ![Language Variant dropdown](images/language-dropdown.png) -2. Click the dropdown and hover over the new language. You will see an **Open in Splitview** option will appear. - - ![Open Language in Splitview](images/open-in-splitview.png) -3. Click **Open in Splitview**. In this splitview, we can see the content node with each language side by side. - - You may notice that the bodytext is greyed out - this is because we haven't checked the **Allow vary by culture** checkbox. - - ![Splitview editing](images/splitview-editing.png) -4. Enter the **Name** for your content node and the **Page Title** in the new language. -5. Click **Save and Publish**. The **Ready to Publish** window opens providing the option to publish in one or more languages. - - ![Publishing Variant content](images/publishing-variant-content.png) -6. You can select either one or multiple languages and click **Publish**. - -## Viewing the Language Variant on the Browser - -To view the language variant on the browser, follow these steps: - -1. Go to the **Content** tab. -2. Select your new language from the language dropdown above your content tree. -3. Select the **Home Page** node and go to the **Info** tab. -4. You will notice the links with the new language domain added to it. If it's not there, you might need to refresh the page. - - ![Viewing the Language Variant Link](images/viewing-langvariant-browser.png) -5. Click on the link to view the new language varied node in the browser. -6. Alternatively, you can add the domain name to your localhost in the browser. For example: [http://localhost:xxxx/dk/](http:/localhost:xxxx/dk/) diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/article-parent-and-article-items.md b/10/umbraco-cms/tutorials/creating-a-basic-website/article-parent-and-article-items.md deleted file mode 100644 index 0dd0c91be7a..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/article-parent-and-article-items.md +++ /dev/null @@ -1,151 +0,0 @@ -# Articles and Article Items - -Having an Articles Parent page, and a number of associated child articles, provides a good example of Umbraco's features. We'll assume our fictional company, Widgets Ltd, writes about ten articles a month and want the articles page to act like a blog. You could use this functionality for news, event pages, or any other collection of Document Types. - -## Creating Articles and Article Items - -Create two new Document Types with template: **Articles Main** and **Articles Item**. - -To create **Articles Main** Document Type, follow these steps: - -1. Go to **Settings**. -2. Select **...** next to the **Document Types** in the **Settings** tree. -3. Click **Document Type with Template**. - - ![Document Type with template](images/Document_type_with_template.png) -4. Enter a **Name** for the **Document Type**. Let's call it _Articles Main_. -5. Let's add two fields with the following specifications: - - | Group | Field Name | Alias | Data Type | - | ----- | ------------------ | ---------------- | ---------------- | - | Intro | Articles Title | articlesTitle | Textstring | - | Intro | Articles Body Text | articlesBodyText | Rich Text Editor | - - ![Articles Main Document Type Data Properties](images/figure-38-articles-main-v8.png) -6. Click **Save** - -To create **Articles Item** Document Type, follow these steps: - -1. Go to **Settings**. -2. Select **...** next to the **Document Types** in the **Settings** tree. -3. Click **Document Type with Template**. - - ![Document Type with template](images/Document_type_with_template.png) -4. Enter a **Name** for the **Document Type**. Let's call it _Articles Item_. -5. Let's add two fields with the following specifications: - - | Group | Field Name | Alias | Data Type | - | ------- | --------------- | -------------- | ---------------- | - | Content | Article Title | articleTitle | Textstring | - | Content | Article Content | articleContent | Rich Text Editor | - - ![Article Item Document Type Data Properties](images/figure-39-articles-item-v8.png) -6. Click **Save** - -### Updating the Document Type Permissions - -To update **Articles Main** Document Type permissions: - -1. Navigate to the **Home Page** Document Type and go to the **Permissions** tab. -2. Select **Add child** in the **Allowed child node types**. The **Choose child node** window opens. -3. Select **Articles Main** and click **Save**. -4. Navigate to the **Articles Main** Document Type and go to the **List View** tab. -5. Toggle **Enable List view** and click **Save**. - - ![Enabling List View](images/figure-44-list-view-enabled.png) - -To update **Articles Item** Document Type permissions: - -1. Navigate to the **Articles Main** Document Type and go to the **Permissions** tab. -2. Select **Add child** in the **Allowed child node types**. The **Choose child node** window opens. -3. Select **Articles Item** and click **Save**. - -## Creating the Content Node - -To add a content node: - -1. Go to **Content**. -2. Select **...** next to the **HomePage** and select **Articles Main**. -3. Enter the name for the article. We are going to call it _Articles_. -4. Enter the **Article Title**, **Article Content**, and click **Save and Publish**. When you click on Save and Publish, you will notice an empty list view is created. - - We still need to add the child nodes which will be displayed in the list view making it easier to view them. You can create new nodes from this section. - - {% hint style="info" %} - If you do not see the list view, try refreshing the page. - {% endhint %} - -5\. Click \*\*Create Articles Item\*\* to add two child nodes called \*\*Article 1\*\*, \*\*Article 2\*\*, and click \*\*Save and Publish\*\*. - -

Content Tree with Articles

- -## Updating the Template - -To update the **Articles Main** template, follow these steps: - -1. Go to **Settings**. -2. Expand the **Templates** folder in the **Templating** section. You should see a template titled _**Articles Main**_. -3. Select **Master** in the **Master template** and click **Save**. -4. Open the **Custom Umbraco Template** folder. -5. Copy the contents of **Blog.html** and paste the content into **Articles Main** below the closing curly brace "}". - * Take care when pasting the template not to overwrite the first line `@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage`. If you get an error when loading the page ensure the last part in <> brackets matches your Document Type alias. -6. Remove everything from the `` (around line 9) to the end of the `` tag (around line 44) which is the `header` and `navigation` of the site since it is already mentioned in the master template. -7. Remove everything from the `` tag (around line 84) to the end of the `` tag (around line 131) -8. Replace the static text within the `

` tags (around line 13) with the Model.Value reference to _**articlesTitle**_. -9. Replace the static text within the `
` tags (from line 24 to 30) with the Model.Value reference to _**articlesBodyText**_. - - ![Articles Main Template](images/articles-main-template-v9.png) -10. Define a query for all articles, just below the `

` tag (around line 32) of the `` section. - - ![Query Builder](images/query-builder-v9.png) -11. You can set conditions to get specific articles or decide the order of the articles. For the purpose of this guide, we'll use the following parameters: - - ![Query parameters](images/query-parameters.png) -12. If you've set the correct parameters, you will get a preview of the items being selected with the query. Click **Submit**, and you will see a code snippet has been added to your template. It will look similar to this:\\ - - ```csharp - @{ - var selection = Umbraco.Content(Guid.Parse("e0a4f1ff-122e-41bd-941c-f9686f03019f")) - .ChildrenOfType("articlesItem") - .Where(x => x.IsVisible()) - .OrderByDescending(x => x.CreateDate); - } -
    - @foreach (var item in selection) - { -
  • - @item.Name() -
  • - } -
- ``` -13. The above code will output a list of all the _**Article Items**_ as links using the name. We will modify the template a little, to add more information about the articles. Replace the `HTML` in the _foreach_ loop with this snippet: - - ```csharp -
- - -
@Html.Truncate(item.Value("articleContent").ToString(), 20, true)Read More..
-
- ``` -14. Click **Save**. - -To update the **Articles Item** template, follow these steps: - -1. Go to **Settings**. -2. Expand the **Templates** folder in the **Templating** section. You should see a template titled _**Articles Item**_. -3. Select **Master** in the **Master template** and click **Save**. -4. Open the **Custom Umbraco Template** folder. -5. Copy the contents of **Blogpost.html** and paste the content into **Articles Item** below the closing curly brace "}". - * Take care when pasting the template not to overwrite the first line `@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage`. If you get an error when loading the page ensure the last part in <> brackets matches your Document Type alias. -6. Remove everything from the `` (around line 9) to the end of the `

` tag (around line 44) which is the `header` and `navigation` of the site since it is already mentioned in the master template. -7. Remove everything from the `` tag (around line 114) to the end of the `` tag (around line 161) -8. Replace the static text within the `

` tags (around line 14) with the Model.Value reference to _**articleTitle**_. -9. Replace the static text within the `
` tags (from line 26 to 41) with the Model.Value reference to _**articleContent**_. - - ![Articles Item Template](images/articles-item-template-v9.png) -10. Click **Save**. - -Check your browser, you should now see something similar to the screen below. - -![Finished Articles section](images/article-main-frontend.png) diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/conclusion.md b/10/umbraco-cms/tutorials/creating-a-basic-website/conclusion.md deleted file mode 100644 index 7e065709fe5..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/conclusion.md +++ /dev/null @@ -1,17 +0,0 @@ ---- - - ---- - -# Conclusions - -We now have a fully fledged working site! Hopefully, this guide has given you all the basics required to create your own site in Umbraco. - -This is not the limit of Umbraco - you've barely scratched the surface in this guide. - -* For Video Tutorials, see the [Umbraco Learning Base Youtube channel](https://www.youtube.com/c/UmbracoLearningBase). -* For hands-on Training and Developer Certification, attend an official Umbraco Master Class course in a city near you. [Book your Online Course now](https://umbraco.com/products/training). -* For Online Documentation, see [the Umbraco Documentation website](../../../README.md). -* For Help and Guidance on anything this guide doesn't cover, reach out to us at [Umbraco Forum](https://our.umbraco.com/forum). - -## Happy Umbraco-ing diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/creating-master-template-part-1.md b/10/umbraco-cms/tutorials/creating-a-basic-website/creating-master-template-part-1.md deleted file mode 100644 index 97b7ba675f2..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/creating-master-template-part-1.md +++ /dev/null @@ -1,237 +0,0 @@ -# Creating a Master Template - -We've seen how to create a **Document Type** and its corresponding **Template**. If you want to create a three-page site containing; Home, News and Contact Us pages, you would create a _**Document Type**_ with a corresponding **Template** and copy the same HTML code into each template. - -If you see yourself repeating the same HTML multiple times in your templates, you might want to consider creating a new master template. - -To create a new master template: - -1. Go to **Settings**. -2. Select **Templates** from the **Templating** section. -3. Select the **...** next to the **Templates** folder and click **Create**. -4. A template opens up in the content editor. Enter a **Name** for the master template. Let's call it _Master_.\\ - -
-5. Click **Save**. - -## Using the Master Template - -To use the master template: - -1. Go to **Settings**. -2. Select **Templates** from the **Templating** section and open the **Homepage** template. -3. Select `Master Template: No Master`. The Master template dialog opens on the right-side of the browser. -4. Select the template called **Master**. This will update the Razor code section from `Layout = null;` to `Layout = "Master.cshtml";` \\ - -
-5. Click **Save**. - -## Updating Templates With the New Master Template - -We now need to move the parts of our HTML template that are common across all templates into the _**Master**_. It might be slightly different for different websites and you'll need to consider if all pages contain a `
` section so that you can update it in the master. - -To update templates with the new master template, follow these steps: - -1. Go to **Settings**. -2. Select **Templates** from the **Templating** section and open the **Homepage** template. -3. For this tutorial, we will cut everything from the `` (around line 9) to the end of the `
` tag (around line 44) which is the `header` and `navigation` of the site to the master template.\\ - -
-4. Click **Save**. -5. Go to the **Master** template and paste this HTML markup after the closing curly brace (around line 9).\\ - -
-6. At the end of this markup, we need to tell Umbraco to insert the child template's content. To do so, add the code _**@RenderBody()**_ at the end.\\ - -
-7. Click **Save**. -8. Repeat the same process for the footer content: - * Go to **Settings > Templates > Homepage template** and cut everything from the `` tag (around line 110) to the end of the `` tag (around line 124) and click **Save**. - * Go to the **Master** template and paste this HTML markup after the _**@RenderBody**_ field we've added.\\ - -
- * Click **Save**. - -Now we've done a lot of work. When we refresh our localhost page, nothing has changed. If you have a compilation error you have perhaps mistyped **@RenderBody()**. - -If you are missing any content (header or footer), check that the templates matches the following: - -### Master Template - -```csharp -@using Umbraco.Cms.Web.Common.PublishedModels; -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@{ - Layout = null; -} - -@* the fun starts here *@ - - - - Welcome - UmbracoTV - - - - - - - - - - -
- -
- - @RenderBody() - - - - - - - - - - -``` - -### Homepage Template - -```csharp -@using Umbraco.Cms.Web.Common.PublishedModels; -@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage -@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; -@{ - Layout = "Master.cshtml"; -} - - - - - -
-
-

@Model.Value("pageTitle")

-

And this is only the beginning.

-
-
- - - -
- -
-
- - @Model.Value("bodyText") - -
-
- -
- - -
-
-
-
-

A flexible CMS - do things your way

-

The Umbraco source code is free and available for download either as a ZIP file or via NuGet under the MIT license, so you can start crafting websites in Umbraco today. - Need to build a site with multiple 3rd party extensions and customized add-ons? No problem. Need to build a simple site with a straightforward contact form? No problem.

-

Whatever type or scale of your project, Umbraco will be able to handle it - and the cherry on top; with Umbraco’s well-known editor friendly UI, - no matter how complex a site you’re building, you know that your editors will still find it a breeze to edit. Oh, and the cherry on top of the cherry - - there's no need for you to spend time learning a new coding or templating language as Umbraco is based on C#, javaScript and Razor.

-
-
- Community illustration -
-
-
-
- - -
- -
-
-

Latest from the blog

-
- - -
-
-
-
Product Update - Deploying Deploy 3.3
-

January 20th 2020 - by Sofie Toft

-

The end of 2019 is approaching and with this, also the last Product Update of the year. - Let’s have a look at what we’ve been working on and what you can expect in the near future.

-
- Read more >> -
-
-
-
-
Umbraco <3 YouTube
-

January 20th 2020 - by Sofie Toft

-

The end of 2019 is approaching and with this, also the last Product Update of the year. - Let’s have a look at what we’ve been working on and what you can expect in the near future.

-
- Read more >> -
-
-
-
-
A day in a Documentation Curators life
-

January 20th 2020 - by Sofie Toft

-

The end of 2019 is approaching and with this, also the last Product Update of the year. - Let’s have a look at what we’ve been working on and what you can expect in the near future.

-
- Read more >> -
-
- -
- - -
-
- -
-
-

How to continue your Umbraco journey

-

What’s next? We have gathered the 3 best ways for you to go on from here ensuring you get the best start to your Umbraco journey:

- 3 ways to start your Umbraco Journey >> -
-
- -
-
-``` diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/creating-master-template-part-2.md b/10/umbraco-cms/tutorials/creating-a-basic-website/creating-master-template-part-2.md deleted file mode 100644 index b4edf599dc3..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/creating-master-template-part-2.md +++ /dev/null @@ -1,120 +0,0 @@ -# Creating Pages and Using the Master Template - -## Creating a Contact Us Page - -We are now going to create a page where we put our contact details. For added functionality, you might want to look at replacing this with a fully fledged contact us form. - -Some potential solutions: - -* If you're not a programmer you can use the Umbraco built-in package - Umbraco Forms. Umbraco Forms has the added benefit that editors can also create their own forms. Find more information and purchase the product through [Umbraco Apps](https://umbraco.com/apps/umbraco-forms/). -* Build your own contact form using [Surface Controllers](../../fundamentals/code/creating-forms.md). - -### Creating the Document Type and Template - -Let's create a content-only contact page where we can provide a title and some rich text. - -1. Go to **Settings**. -2. Select the **...** next to the **Document Types** in the **Settings** tree. -3. Select **Document Type with Template**. The Document Type opens in the content editor. -4. Select an **Icon** from the list of icons. -5. Enter a **Name**. Let's call it _Simple Content Page_. -6. Enter a Description. -7. Let's add two fields with the following specifications: - - | Group | Field Name | Alias | Data Type | - | ------- | ---------- | --------- | ---------------- | - | Content | Page Title | pageTitle | Textstring | - | Content | Body Text | bodyText | Rich Text Editor | - - ![Simple Content Page Template with Data Fields](images/figure-35-contact-us-template-with-data-fields-v8.png) -8. Click **Save**. -9. Go to **Templates** to view your _Simple Content Page_ template that was created automatically with the Document Type. -10. Select the **Simple Content Page** template and then select **Master** as the **Master template**. -11. Add the following HTML to the **Simple Content Page** template and click **Save**. - - ```html - -
-
-

Umbraco Support

-
-
- - -
-
- -

Are you a developer?

-

Are you a marketer?

-

Are you working at an agency?

-

Let Umbraco unleash your talent

-
-
- ``` -12. Click **Save**. - -### Updating the Document Type Permissions - -We now need to update the Document Type permissions to specifically add child nodes under the root content node. - -To update the Document Type permissions: - -1. Go to **Settings**. -2. Open the **Homepage** Document Type and go to the **Permissions** tab. -3. Select **Add child** in the **Allowed child node types**. The **Choose child node** dialog opens. -4. Select **Simple Content Page** and click **Save**.\\ - -
- -### Creating the content node - -To create a content node: - -1. Go to **Content**. -2. Select **...** next to the **Homepage** and select **Simple Content Page**. -3. Enter a name for the Document Type. Let's call it _Contact Us_. -4. Fill in details for the **Page Title** and **Body Text**. -5. Click **Save and Publish**. - -### Adding the Document Type Properties - -To add the Document Type properties: - -1. Go to **Settings**. -2. Select **Templates** from the **Templating** section, and open the **Simple Content Page** template. -3. Scroll to the `` (around line 8) section and highlight the text `“Umbraco Support”` (around line 11). -4. Click **Insert** and select **Value**. -5. Select the **pageTitle** field from the drop-down list and click **Submit**. -6. Repeat the same process for the `
` tag: - * Highlight the content from the `

` tag (around line 19) to the end of the `

` tag (around line 22). - * Click **Insert** and select **Value**. - * Select **bodyText** field from the drop-down list. - * Click **Submit**. -7. Click **Save**. - -### Viewing the Contact Us Page - -To view the **Contact Us** Page: - -1. Go to **Content**. -2. Select the **Contact Us** page. -3. Go to the **Info** tab. -4. Click the link to view the page. \\ - -
- -## Using Document Type Properties from the Homepage - -You may notice that the footer is now empty - we don't have the content from our Homepage node. - -To use the Document Type properties from the homepage, do the following: - -1. Go to **Settings**. -2. Select **Templates** from the **Templating** section, and open the **Master** template. -3. Highlight `@Model.Value("footerText")` in the footer (around line 52) and click **Insert**. -4. Select **Value** and choose the **footerText** again from the **Choose field** dropdown. -5. Select **Yes, make it recursive** checkbox. This notifies Umbraco to look up the content tree if the field doesn't exist at the node level for the page we're requesting. -6. Click **Submit**. -7. Click **Save**. - -Reload the _Contact Us_ page to view the content with the footer. diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/creating-your-first-template-and-content-node.md b/10/umbraco-cms/tutorials/creating-a-basic-website/creating-your-first-template-and-content-node.md deleted file mode 100644 index 2ade6c840c5..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/creating-your-first-template-and-content-node.md +++ /dev/null @@ -1,57 +0,0 @@ -# Creating Your First Template - -Umbraco creates a corresponding template when you select the **Document Type with Template** option when creating a Document Type. - -To edit the template: - -1. Go to **Settings**. -2. Expand the **Templates** folder in the **Templating** section of the tree. You should see a template titled _**HomePage**_. -3. Open the template. It will contain a little bit of _**Razor code**_.\ - \\ - -
-4. Leaving the code that's there (if you don't understand it, don't worry!) let's copy our template code in. - * We are using files from the [Custom Umbraco Template](https://umbra.co/Umbracotemplate). -5. Open the **Custom Umbraco Template** folder and copy the contents of **index.html**. -6. Paste the content into the _HomePage_ template below the closing curly brace "}". - * Umbraco _**Templates**_ use _**Razor**_ which allows you to add code in your _**Template**_ files. _**Razor**_ reacts to `@` signs. -7. Click **Save**. - -We now have a _Template_. That's two out of the three stages complete for our first page. - -## Creating Your First content node - -Our third and final stage to creating our first page in Umbraco, is to create a _**content node**_ that uses our _**Document Type**_ and _**Template**_, to serve up an HTML page to web visitors. - -To add a content node: - -1. Go to **Content**. -2. Select **...** next to the **Content** headline in the tree. Select **HomePage**.\ - \\ - - * If you cannot see the content node, check that \[Settings] > \[Document Types] > \[HomePage] > \[Permissions tab] > \[Allow at root] is checked. The Home Page opens in the content editor. - -
-3. Enter the name for the content node. We are going to call this _Homepage_. - * The name will show up in the node list and will be used to create a url for the page. Try to keep it short but descriptive. -4. Enter the following details: - - | Name | Description | - | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | - | Page Title | Welcome to Widgets Ltd | - | Body Text |

Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam et aliquet ante, ut eleifend libero.

  • Proin eleifend consequat nunc id vulputate.
  • Ut eget lobortis metus, non congue lorem.
  • Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
  • Maecenas tempus non lectus rhoncus efficitur.

Sed est ligula, maximus in dolor sed, lacinia egestas ligula. Donec eu nisi lectus.

Morbi pharetra pulvinar arcu non gravida.

| - | Footer Text | Copyright Widgets Ltd 2019 | -5. Click **Save and Publish**. The content tree will reload with the homepage node. - -Refresh your webpage in your browser [http://localhost:xxxx](http:/localhost:xxxx/). To access your webpage: - -1. In the **Homepage** content node, select **Info**. -2. Click on the window pop-up symbol under the **Links** section. - -The default Umbraco page will now be gone and we'll now see a very bare, unstyled page. We are getting there. - -{% hint style="info" %} -If you see a blank page, check if the template is entered and remember to save it. -{% endhint %} - -![An Unstyled Homepage](images/figure-16-unstyled-homepage-v8.png) diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/css-and-images.md b/10/umbraco-cms/tutorials/creating-a-basic-website/css-and-images.md deleted file mode 100644 index f9f9739efcc..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/css-and-images.md +++ /dev/null @@ -1,27 +0,0 @@ -# CSS and Images - -Our homepage is currently missing the CSS and image files. To include these files: - -1. Open File Explorer and navigate to both your Umbraco project folder and the **Custom Umbraco Template** folder. - -{% hint style="info" %} -The Umbraco project folder refers to the folder created during the [Umbraco installation](../../fundamentals/setup/install/). -{% endhint %} - -2. Copy the **css** and **images** folders from the _Custom Umbraco template_ folder. -3. Paste them inside the **wwwroot** folder of your Umbraco project. -4. Go to the **HomePage** template in the **Settings** section. -5. Make sure the stylesheet reference in the HTML is `/css/main.css`. - - ![Stylesheet reference](images/stylesheet-reference.png) - -## Stylesheet Reference - -Use the Developer Tools in Chrome/Firefox/Edge and refresh `http://localhost:xxxx.` - -* Check the **Network** tab to confirm no CSS or image files are missing. -* If you see any errors, double-check for typos and confirm the folders are placed correctly inside the **wwwroot** folder of your Umbraco project. - -## How Static Files Are Served - -Umbraco serves static files such as stylesheets and images from the **wwwroot** folder. This folder acts as the web root in ASP.NET Core applications. Any files placed here are publicly accessible and can be served directly by the application when requested by the browser. diff --git a/10/umbraco-cms/tutorials/creating-a-basic-website/displaying-the-document-type-properties.md b/10/umbraco-cms/tutorials/creating-a-basic-website/displaying-the-document-type-properties.md deleted file mode 100644 index 336ba248821..00000000000 --- a/10/umbraco-cms/tutorials/creating-a-basic-website/displaying-the-document-type-properties.md +++ /dev/null @@ -1,45 +0,0 @@ -# Displaying the Document Type Properties - -You might have noticed that the content we've added to the homepage is not being displayed. We need to wire up the Data Type properties to the template. - -Let’s look at our template and identify where the content should be displayed. - -![Where our Data Properties Content Should be Output](images/figure-17-where-our-data-fields-go-v8.png) - -The top arrow in this image is the _Page Title_ and the bottom arrow is the _Body Text_, whereas the Footer is all the way at the bottom. - -## Setting the Document Type Properties - -To set the Document Type properties: - -1. Go to **Settings**. -2. Select **Templates** in the **Templating** section, and open the **Homepage** template. -3. Scroll down to the `` section (around line 46) and highlight the text `“Welcome - UmbracoTV”` (around line 49).\\ - -
-4. Click **Insert** and select **Value**. -5. Select **pageTitle** field from the drop-down list.\\ - -
-6. Click **Submit**. -7. Repeat the same process for the content between the `
` tags (around line 61 to 78): - * Highlight the content as shown in the figure.\\ - -
- * Click **Insert** and select **Value**. - * Select **bodyText** field from the drop-down list. - * Click **Submit**. -8. Repeat the same process for the content in the `