{"id":1896492,"date":"2019-10-18T13:19:15","date_gmt":"2019-10-18T17:19:15","guid":{"rendered":"https:\/\/theeventscalendar.com\/knowledgebase\/tribe-settings-api-2\/"},"modified":"2026-04-23T15:42:04","modified_gmt":"2026-04-23T19:42:04","slug":"tribe-settings-api","status":"publish","type":"post","link":"https:\/\/theeventscalendar.com\/knowledgebase\/tribe-settings-api\/","title":{"rendered":"Customize The Events Calendar Settings with the Tribe Settings API"},"content":{"rendered":"\n<p id=\"tribesettingsapi\">If you&#8217;re writing a custom add-on, a site-specific plugin, or a code snippet that extends <a href=\"https:\/\/theeventscalendar.com\/products\/wordpress-events-calendar\/\">The Events Calendar<\/a> or <a href=\"https:\/\/theeventscalendar.com\/products\/wordpress-event-tickets\/\">Event Tickets<\/a>, the Tribe Settings API gives you a clean way to plug your own options into the existing settings screens &#8211; the same API our own tabs (General, Display, Integrations, etc.) are built on. Instead of reinventing a settings page with the WordPress Settings API, you can register a tab, add fields, and let Tribe Settings handle the rendering, validation, saving, and error messaging for you.<\/p>\n\n\n\n<p>The API was originally introduced in The Events Calendar 2.0.5 and has since been extracted into the shared <a href=\"https:\/\/github.com\/the-events-calendar\/tribe-common\" target=\"_blank\" rel=\"noreferrer noopener\">tribe-common<\/a> library (<code>@since 4.0.1<\/code>), where it is bootstrapped and loaded on every request for any plugin that embeds tribe-common (The Events Calendar, Event Tickets, and their add-ons). Four classes make up the API, and all four live in the <em>\/common\/src\/Tribe\/<\/em> folder of the plugin. The older <em>Tribe__Events__*<\/em> class names still exist as deprecated shims under <em>\/common\/src\/deprecated\/<\/em>, but new code should use the current class names listed below.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-how-the-four-classes-fit-together\">How the four classes fit together<\/h2>\n\n\n\n<p>Each class sits at a different level of abstraction. In practice you&#8217;ll usually only touch the last one:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Tribe__Settings<\/strong> &#8211; the top-level controller. It owns the list of tabs, routes the current request to the right tab, and dispatches the full render \/ validate \/ save lifecycle. You rarely instantiate this yourself; it&#8217;s constructed by tribe-common. You <em>do<\/em> hook into its actions and filters to inject content.<\/li>\n\n\n\n<li><strong>Tribe__Field<\/strong> &#8211; renders an individual field (text box, dropdown, toggle, etc.). You pass it an array describing the field and it outputs the HTML. Usable anywhere &#8211; settings, metaboxes, user profile screens &#8211; not just inside a tab.<\/li>\n\n\n\n<li><strong>Tribe__Validate<\/strong> &#8211; validates and sanitizes a single field&#8217;s value based on a validation type (e.g. <em>url<\/em>, <em>positive_int<\/em>, <em>email<\/em>). Also usable standalone, but in a settings tab it&#8217;s invoked automatically on save.<\/li>\n\n\n\n<li><strong>Tribe__Settings_Tab<\/strong> &#8211; the public API. Instantiating this class registers a new tab, its fields, and its defaults. It wires the other three classes together so you don&#8217;t have to.<\/li>\n<\/ul>\n\n\n\n<p>If you&#8217;re creating a new tab, <em>Tribe__Settings_Tab<\/em> is where you should focus. The other three are documented below for when you need to reach a level deeper &#8211; for example, rendering a single field in a metabox, adding a custom validation rule, or modifying what another plugin&#8217;s tab renders via hooks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-quick-start-register-a-tab-in-20-lines\">Quick start: register a tab in ~20 lines<\/h2>\n\n\n\n<p>A minimal working example that adds a <em>My Add-on<\/em> tab to the Events settings screen with a single text field. All fields in this example save as entries in the serialized <em>Tribe__Main::OPTIONNAME<\/em> array, which is the same array the rest of The Events Calendar uses &#8211; you can read them back with <code>tribe_get_option( 'my_addon_api_key' )<\/code>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_action( &#039;tribe_settings_do_tabs&#039;, function () {\n\t$fields = &#x5B;\n\t\t&#039;my_addon_heading&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039; =&gt; &#039;heading&#039;,\n\t\t\t&#039;label&#039; =&gt; __( &#039;My Add-on Settings&#039;, &#039;my-addon&#039; ),\n\t\t],\n\t\t&#039;my_addon_api_key&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039;            =&gt; &#039;text&#039;,\n\t\t\t&#039;label&#039;           =&gt; __( &#039;API key&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;tooltip&#039;         =&gt; __( &#039;Paste the API key from your dashboard.&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;validation_type&#039; =&gt; &#039;alpha_numeric_with_dashes_and_underscores&#039;,\n\t\t\t&#039;can_be_empty&#039;    =&gt; true,\n\t\t],\n\t\t&#039;my_addon_enabled&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039;            =&gt; &#039;toggle&#039;,\n\t\t\t&#039;label&#039;           =&gt; __( &#039;Enable integration&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;default&#039;         =&gt; false,\n\t\t\t&#039;validation_type&#039; =&gt; &#039;boolean&#039;,\n\t\t],\n\t];\n\n\tnew Tribe__Settings_Tab(\n\t\t&#039;my-addon&#039;,                         \/\/ Tab ID (used in the URL).\n\t\t__( &#039;My Add-on&#039;, &#039;my-addon&#039; ),      \/\/ Tab label.\n\t\t&#x5B;\n\t\t\t&#039;priority&#039; =&gt; 55,               \/\/ Places the tab between Licenses (40) and Help (60).\n\t\t\t&#039;fields&#039;   =&gt; $fields,\n\t\t]\n\t);\n} );\n<\/pre><\/div>\n\n\n<p>The <em>tribe_settings_do_tabs<\/em> action is the standard entry point for registering tabs &#8211; firing your <em>new Tribe__Settings_Tab()<\/em> call inside it ensures the tab is registered at the right moment in the lifecycle. See the <a href=\"#h-priority\">Priority<\/a> section below for how to position your tab relative to the existing ones.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-class-reference\">Class reference<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"classtribesettings\">Class <em>Tribe__Settings<\/em><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>File: <em>\/common\/src\/Tribe\/Settings.php<\/em><\/li>\n\n\n\n<li>Description: static helper class that allows registration of settings; instantiation takes place in tribe-common on the <em>tec_settings_init<\/em> action.<\/li>\n\n\n\n<li>Deprecated alias: <em>Tribe__Events__Settings<\/em> (see <em>\/common\/src\/deprecated\/Tribe__Events__Settings.php<\/em>).<\/li>\n<\/ul>\n\n\n\n<p><strong>Class variables:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>$instance<\/em>: (stdClass) singleton method instance var<\/li>\n\n\n\n<li><em>$tabs<\/em>: (array) the tabs that will appear in the settings page (filtered on class construct)<\/li>\n\n\n\n<li><em>$fields<\/em>: (array) multidimensional array of the fields that will be generated for the entire settings panel, tabs are represented in the array keys<\/li>\n\n\n\n<li><em>$defaultTab<\/em>: (string) the default tab for the settings panel, this should be a tab ID<\/li>\n\n\n\n<li><em>$currentTab<\/em>: (string) the current tab being displayed<\/li>\n\n\n\n<li><em>$noSaveTabs<\/em>: (array) tabs that shouldn&#8217;t show the save button<\/li>\n\n\n\n<li><em>$adminSlug<\/em>: (string) the slug used in the admin to generate the settings page<\/li>\n\n\n\n<li><em>$menuName<\/em>: (string) the menu name used for the settings page<\/li>\n\n\n\n<li><em>$requiredCap<\/em>: (string) the required capability for the settings page<\/li>\n\n\n\n<li><em>$errors<\/em>: (mixed) errors that occur after a save operation<\/li>\n\n\n\n<li><em>$saved<\/em>: (bool) true when just saved<\/li>\n\n\n\n<li><em>$admin_page<\/em>: (string) the <em>$current_screen<\/em> name corresponding to the admin page<\/li>\n\n\n\n<li><em>$major_error<\/em>: (bool) true if a major error that prevents saving occurred<\/li>\n\n\n\n<li><em>$validated<\/em>: (array) holds validated fields<\/li>\n<\/ul>\n\n\n\n<p><strong>Action Hooks:<\/strong><\/p>\n\n\n\n<p>Tribe__Settings fires a large number of actions. They&#8217;re grouped below by when they run, so you can pick the right place to inject content or behavior.<\/p>\n\n\n\n<p><em>Registration &amp; page chrome (most common)<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>tribe_settings_do_tabs<\/em>: register new tabs here (used with the <em>Tribe__Settings_Tab<\/em> class)<\/li>\n\n\n\n<li><em>tribe_settings_after_do_tabs<\/em>: occurs after all tabs are added<\/li>\n\n\n\n<li><em>tribe_settings_top<\/em>: occurs before opening <em>&lt;div class=&#8221;tribe_settings wrap&#8221;&gt;<\/em> of the settings page<\/li>\n\n\n\n<li><em>tribe_settings_above_tabs<\/em>: occurs right above the tabs (below the title)<\/li>\n\n\n\n<li><em>tribe_settings_below_tabs<\/em>: occurs right below the tabs<\/li>\n\n\n\n<li><em>tribe_settings_below_tabs_tab_{$currentTab}<\/em>: occurs right below the tabs for the specified tab<\/li>\n\n\n\n<li><em>tribe_settings_after_tabs<\/em>: occurs after tabs<\/li>\n\n\n\n<li><em>tribe_settings_bottom<\/em>: occurs at the bottom of the settings screen<\/li>\n<\/ul>\n\n\n\n<p><em>Form rendering<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>tribe_settings_above_form_element<\/em>: occurs above the form element<\/li>\n\n\n\n<li><em>tribe_settings_above_form_element_tab_{$currentTab}<\/em>: occurs above the form element for the specified tab<\/li>\n\n\n\n<li><em>tribe_settings_before_content<\/em>: occurs after the form element<\/li>\n\n\n\n<li><em>tribe_settings_before_content_tab_{$currentTab}<\/em>: occurs after the form element for the specified tab<\/li>\n\n\n\n<li><em>tribe_settings_content_tab_{$currentTab}<\/em>: generates the content for the specified tab<\/li>\n\n\n\n<li><em>tribe_settings_after_content_tab_{$currentTab}<\/em>: occurs after the content for the specified tab<\/li>\n\n\n\n<li><em>tribe_settings_after_content<\/em>: occurs after the content<\/li>\n\n\n\n<li><em>tribe_settings_after_form_element<\/em>: occurs after the form element<\/li>\n\n\n\n<li><em>tribe_settings_after_form_element_tab_{$currentTab}<\/em>: occurs after the form element for the specified tab<\/li>\n\n\n\n<li><em>tribe_settings_after_form_div<\/em>: occurs after the closing form div<\/li>\n<\/ul>\n\n\n\n<p><em>Validation &amp; save<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>tribe_settings_validate_before_checks<\/em>: occurs during validation, before any kind of checks are made<\/li>\n\n\n\n<li><em>tribe_settings_validate<\/em>: occurs in validation once the permission, nonce and tab checks are made<\/li>\n\n\n\n<li><em>tribe_settings_validate_tab_{$currentTab}<\/em>: same as <em>tribe_settings_validate<\/em> but for a specific tab<\/li>\n\n\n\n<li><em>tribe_settings_validate_field<\/em>: occurs on field validation<\/li>\n\n\n\n<li><em>tribe_settings_validate_field_{$field_id}<\/em>: occurs on specific field validation<\/li>\n\n\n\n<li><em>tribe_settings_save<\/em>: occurs on save<\/li>\n\n\n\n<li><em>tribe_settings_save_tab_{$currentTab}<\/em>: occurs on save for specific tab<\/li>\n\n\n\n<li><em>tribe_settings_save_field<\/em>: occurs on field save<\/li>\n\n\n\n<li><em>tribe_settings_save_field_{$field_id}<\/em>: occurs on specific field save<\/li>\n<\/ul>\n\n\n\n<p><strong>Filter Hooks:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>tribe_settings_menu_name<\/em>: filter the settings panel&#8217;s menu name<\/li>\n\n\n\n<li><em>tribe_settings_req_cap<\/em>: filter the required capability, defaults to <em>manage_options<\/em><\/li>\n\n\n\n<li><em>tribe_settings_admin_slug<\/em>: filter the admin slug for the settings page<\/li>\n\n\n\n<li><em>tribe_settings_tabs<\/em>: filter the tabs for the settings panel<\/li>\n\n\n\n<li><em>tribe_settings_fields<\/em>: filter the fields for the settings panel<\/li>\n\n\n\n<li><em>tribe_settings_default_tab<\/em>: filter the default tab, defaults to <em>general<\/em><\/li>\n\n\n\n<li><em>tribe_settings_current_tab<\/em>: filter the current tab, defaults to <em>$_GET[&#8216;tab&#8217;]<\/em><\/li>\n\n\n\n<li><em>tribe_settings_no_save_tabs<\/em>: filter which tabs don&#8217;t have the save tab<\/li>\n\n\n\n<li><em>tribe_settings_form_element<\/em>: filter the opening form element for the settings panel, defaults to <em>&lt;form method=&#8221;post&#8221;&gt;<\/em><\/li>\n\n\n\n<li><em>tribe_settings_closing_form_element<\/em>: filter the closing form element for the settings panel, defaults to <em>&lt;\/form&gt;<\/em><\/li>\n\n\n\n<li><em>tribe_settings_validate_field_value<\/em>: filter a field&#8217;s value before we validate it<\/li>\n\n\n\n<li><em>tribe_settings_save_field_value<\/em>: filter a field&#8217;s value before we save it<\/li>\n\n\n\n<li><em>tribe_settings_save_field_parent_option<\/em>: filter a field&#8217;s parent array option id before saving it<\/li>\n\n\n\n<li><em>tribe_settings_save_option_array<\/em>: filter an option array before saving it<\/li>\n\n\n\n<li><em>tribe_settings_display_errors<\/em>: filter the <em>$errors<\/em> array before displaying it<\/li>\n\n\n\n<li><em>tribe_settings_count_errors<\/em>: filter how many errors there are before displaying them<\/li>\n\n\n\n<li><em>tribe_settings_display_errors_or_not<\/em>: determine whether to display errors or not, defaults to whether the error count is above zero or not<\/li>\n\n\n\n<li><em>tribe_settings_error_message<\/em>: filter the full error message<\/li>\n\n\n\n<li><em>tribe_settings_success_message<\/em>: filter the success message<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"classtribefield\">Class <em>Tribe__Field<\/em><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>File: <em>\/common\/src\/Tribe\/Field.php<\/em><\/li>\n\n\n\n<li>Description: helper class that creates fields for use in Settings, MetaBoxes, Users, anywhere. Instantiate it whenever you need a field.<\/li>\n\n\n\n<li>Deprecated alias: <em>Tribe__Events__Field<\/em> (see <em>\/common\/src\/deprecated\/Tribe__Events__Field.php<\/em>).<\/li>\n<\/ul>\n\n\n\n<p><strong>Class variables:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>$id<\/em>: (string) the field&#8217;s id<\/li>\n\n\n\n<li><em>$name<\/em>: (string) the field&#8217;s name (also known as its label)<\/li>\n\n\n\n<li><em>$args<\/em>: (array) the field&#8217;s arguments<\/li>\n\n\n\n<li><em>$defaults<\/em>: (array) field defaults (static)<\/li>\n\n\n\n<li><em>$valid_field_types<\/em>: (array) the valid field types<\/li>\n<\/ul>\n\n\n\n<p><strong>Constructor variables:<\/strong><\/p>\n\n\n\n<p>These variables are passed to the class when it is instantiated, like so:<\/p>\n\n\n\n<p><em>new Tribe__Field($id, $field, $value = null)<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>$id<\/em>: (string) the field&#8217;s id<\/li>\n\n\n\n<li><em>$field<\/em>: (array) the field object\/arguments<\/li>\n\n\n\n<li><em>$value<\/em>: (mixed)[optional] the field&#8217;s current value<\/li>\n<\/ul>\n\n\n\n<p><strong>Field Arguments:<\/strong><\/p>\n\n\n\n<p>These are set with the <em>$args<\/em> variable. Below are the different arguments with their default value:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8216;type&#8217; =&gt; &#8216;html&#8217;, the field type<\/li>\n\n\n\n<li>&#8216;name&#8217; =&gt; $id, the field&#8217;s name attribute (used in <em>$_POST<\/em>)<\/li>\n\n\n\n<li>&#8216;class&#8217; =&gt; null, class to be applied to the field&#8217;s <em>&lt;fieldset&gt;<\/em> element<\/li>\n\n\n\n<li>&#8216;label&#8217; =&gt; null, the field&#8217;s label<\/li>\n\n\n\n<li>&#8216;tooltip&#8217; =&gt; null, the field&#8217;s description\/label, used in the tooltip as well as in the screen reader label<\/li>\n\n\n\n<li>&#8216;size&#8217; =&gt; &#8216;medium&#8217;, (possible values are small, medium or large) this applies to text, text area, dropdown, and license_key fields only<\/li>\n\n\n\n<li>&#8216;html&#8217; =&gt; null, the html of a field (applies only to an html field)<\/li>\n\n\n\n<li>&#8216;error&#8217; =&gt; false, boolean to indicate if the field is currently erroneous or not &#8211; this is set via <em>Tribe__Validate<\/em><\/li>\n\n\n\n<li>&#8216;value&#8217; =&gt; $value, the current value for the field<\/li>\n\n\n\n<li>&#8216;options&#8217; =&gt; null, options for the field (this applies to radio and dropdown fields only)<\/li>\n\n\n\n<li>&#8216;conditional&#8217; =&gt; true, allows you to set a condition on a field to determine whether it should appear or not, you can pass a function, a variable, whatever you want here, but it expects a boolean value<\/li>\n\n\n\n<li>&#8216;display_callback&#8217; =&gt; null, a function name to generate the field with, this would overwrite the class&#8217; behaviour and generate the field with the specified function instead<\/li>\n\n\n\n<li>&#8216;if_empty&#8217; =&gt; null, optional message to display for a radio or dropdown button when <em>$options<\/em> are empty, handy for dynamic fields<\/li>\n\n\n\n<li>&#8216;can_be_empty&#8217; =&gt; false, allows a field to be saved with an empty value<\/li>\n\n\n\n<li>&#8216;clear_after&#8217; =&gt; true, to add a <em>&lt;div class=&#8221;clear&#8221;&gt;&lt;\/div&gt;<\/em> after the field or not, defaults to add it<\/li>\n<\/ul>\n\n\n\n<p><strong>Valid Field Types:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>heading: an <em>&lt;h3&gt;<\/em> wrapped heading<\/li>\n\n\n\n<li>html: arbitrary html code<\/li>\n\n\n\n<li>wrapped_html: arbitrary html code with a wrapper element<\/li>\n\n\n\n<li>text: regular text field<\/li>\n\n\n\n<li>textarea: regular text area field<\/li>\n\n\n\n<li>wysiwyg: rich text (TinyMCE) field<\/li>\n\n\n\n<li>email: email text field<\/li>\n\n\n\n<li>number: numeric input field<\/li>\n\n\n\n<li>color: color-picker field<\/li>\n\n\n\n<li>radio: radio buttons<\/li>\n\n\n\n<li>checkbox_bool: single checkbox (true or false)<\/li>\n\n\n\n<li>checkbox_list: checkbox list with options<\/li>\n\n\n\n<li>toggle: on\/off toggle switch<\/li>\n\n\n\n<li>dropdown: regular <em>&lt;select&gt;<\/em> dropdown<\/li>\n\n\n\n<li>image \/ image_id: media-library image pickers<\/li>\n\n\n\n<li>license_key: regular text field used for entering a license key<\/li>\n<\/ul>\n\n\n\n<p><strong>Note:<\/strong> <em>dropdown_chosen<\/em> and <em>dropdown_select2<\/em> are still recognized but are deprecated &#8211; use <em>dropdown<\/em> instead. Additional field types may be added in future versions of this API.<\/p>\n\n\n\n<p><strong>Action Hooks:<\/strong><\/p>\n\n\n\n<p>None for this class<\/p>\n\n\n\n<p><strong>Filter Hooks:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>tribe_valid_field_types<\/em>: filter valid field types<\/li>\n\n\n\n<li><em>tribe_field_id<\/em>: filter the field&#8217;s id<\/li>\n\n\n\n<li><em>tribe_field_{$key}<\/em>: filter the field&#8217;s specified property<\/li>\n\n\n\n<li><em>tribe_field_output_{$type}<\/em>: filter the specified field type&#8217;s output<\/li>\n\n\n\n<li><em>tribe_field_output_{$type}_{$field_id}<\/em>: filter the specified field&#8217;s output<\/li>\n\n\n\n<li><em>tribe_field_start<\/em>: filter the field start output<\/li>\n\n\n\n<li><em>tribe_field_end<\/em>: filter the field end output<\/li>\n\n\n\n<li><em>tribe_field_label<\/em>: filter the field&#8217;s label output<\/li>\n\n\n\n<li><em>tribe_field_div_start<\/em>: filter the field&#8217;s encompassing div&#8217;s output<\/li>\n\n\n\n<li><em>tribe_field_div_end<\/em>: filter the field&#8217;s closing div&#8217;s output<\/li>\n\n\n\n<li><em>tribe_field_tooltip<\/em>: filter the field&#8217;s <em>title<\/em> attribute output, which is used for the tooltip<\/li>\n\n\n\n<li><em>tribe_field_screen_reader_label<\/em>: filter the field&#8217;s screen reader label<\/li>\n\n\n\n<li><em>tribe_field_value<\/em>: filter the field&#8217;s value attribute<\/li>\n\n\n\n<li><em>tribe_field_name<\/em>: filter the field&#8217;s name attribute<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"classtribevalidate\">Class <em>Tribe__Validate<\/em><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>File: <em>\/common\/src\/Tribe\/Validate.php<\/em><\/li>\n\n\n\n<li>Description: helper class that validates fields for use in Settings, MetaBoxes, Users, anywhere. Instantiate whenever you want to validate a field.<\/li>\n\n\n\n<li>Deprecated alias: <em>Tribe__Events__Validate<\/em> (see <em>\/common\/src\/deprecated\/Tribe__Events__Validate.php<\/em>).<\/li>\n<\/ul>\n\n\n\n<p><strong>Class variables:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>$field<\/em>: (array), the field object to validate<\/li>\n\n\n\n<li><em>$value<\/em>: (mixed), the field&#8217;s value<\/li>\n\n\n\n<li><em>$additional_args<\/em>: (array) additional arguments for validation &#8211; used by some methods only<\/li>\n\n\n\n<li><em>$label<\/em>: (string), the field&#8217;s label, used in error messages<\/li>\n\n\n\n<li><em>$type<\/em>: (string), the type of validation to perform<\/li>\n\n\n\n<li><em>$result<\/em>: (stdClass), the result object of the validation<\/li>\n<\/ul>\n\n\n\n<p><strong>Valid Validation Types:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>not_empty<\/em>: validates that a field is not empty<\/li>\n\n\n\n<li><em>positive_int<\/em>: validates &amp; sanitizes fields as being positive integers<\/li>\n\n\n\n<li><em>slug<\/em>: validates &amp; sanitizes fields as URL slugs<\/li>\n\n\n\n<li><em>url<\/em>: validates &amp; sanitizes fields as URLs<\/li>\n\n\n\n<li><em>email<\/em> \/ <em>email_list<\/em>: validates &amp; sanitizes a single email address or a list of email addresses<\/li>\n\n\n\n<li><em>alpha_numeric<\/em>: validates &amp; sanitizes a field as alphanumeric<\/li>\n\n\n\n<li><em>alpha_numeric_multi_line<\/em>: alphanumeric allowing line breaks<\/li>\n\n\n\n<li><em>alpha_numeric_multi_line_with_dots_and_dashes<\/em>: alphanumeric allowing dots, dashes and line breaks<\/li>\n\n\n\n<li><em>alpha_numeric_with_dashes_and_underscores<\/em>: alphanumeric allowing dashes and underscores<\/li>\n\n\n\n<li><em>options<\/em>: validates fields that have options (radios, dropdowns, etc.) by making sure the value is part of the options array<\/li>\n\n\n\n<li><em>options_multi<\/em> \/ <em>options_with_label<\/em>: variants of <em>options<\/em> for multi-select fields and label-keyed options arrays<\/li>\n\n\n\n<li><em>cannot_be_the_same_as<\/em>: validates &amp; sanitizes fields as not being able to be the same as the specified value, use <em>$additional_args[&#8216;compare&#8217;]<\/em> to pass the value to compare against, and <em>$additional_args[&#8216;compare_name&#8217;]<\/em> to pass the name of what you are comparing against (for the error message)<\/li>\n\n\n\n<li><em>number_or_percent<\/em>: validates fields as being a number or a percentage<\/li>\n\n\n\n<li><em>html<\/em>: sanitizes an html field<\/li>\n\n\n\n<li><em>license_key<\/em>: validates &amp; sanitizes a license key<\/li>\n\n\n\n<li><em>textarea<\/em>: sanitizes a textarea field<\/li>\n\n\n\n<li><em>boolean<\/em>: sanitizes fields as being a boolean<\/li>\n\n\n\n<li><em>color<\/em>: validates &amp; sanitizes a hex color value<\/li>\n\n\n\n<li><em>google_maps_zoom<\/em>: validates a google map zoom level<\/li>\n\n\n\n<li><em>address<\/em>: validates fields as being part of an address, allows for letters, numbers, dashes and spaces only<\/li>\n\n\n\n<li><em>city_or_province<\/em>: validates fields as being a city or province, allows for letters, dashes and spaces only<\/li>\n\n\n\n<li><em>zip<\/em>: validates fields as being a zip code<\/li>\n\n\n\n<li><em>phone<\/em>: validates fields as being a phone number<\/li>\n\n\n\n<li><em>country_list<\/em>: validates &amp; sanitizes a field as being a country list<\/li>\n\n\n\n<li><em>none<\/em>: automatically validate a field regardless of the value. Don&#8217;t use this unless you know what you are doing.<\/li>\n<\/ul>\n\n\n\n<p><strong>NOTE:<\/strong> more validation types will surely be added in future versions of this API.<\/p>\n\n\n\n<p><strong>Action Hooks:<\/strong><\/p>\n\n\n\n<p>None for this class<\/p>\n\n\n\n<p><strong>Filter Hooks:<\/strong><\/p>\n\n\n\n<p>None for this class<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"classtribesettingstab\">Class <em>Tribe__Settings_Tab<\/em><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>File: <em>\/common\/src\/Tribe\/Settings_Tab.php<\/em><\/li>\n\n\n\n<li>Description: helper class that creates a settings tab; this is a public API, use it to create tabs simply by instantiating this class.<\/li>\n\n\n\n<li>Deprecated alias: <em>Tribe__Events__Settings_Tab<\/em> (see <em>\/common\/src\/deprecated\/Tribe__Events__Settings_Tab.php<\/em>).<\/li>\n<\/ul>\n\n\n\n<p><strong>Class variables:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>$id<\/em>: (string) Tab ID, used in query string and elsewhere<\/li>\n\n\n\n<li><em>$name<\/em>: (string) Tab&#8217;s name<\/li>\n\n\n\n<li><em>$args<\/em>: (array) Tab&#8217;s arguments<\/li>\n\n\n\n<li><em>$defaults<\/em>: (array) Defaults for tabs<\/li>\n<\/ul>\n\n\n\n<p><strong>Action Hooks:<\/strong><\/p>\n\n\n\n<p>None for this class<\/p>\n\n\n\n<p><strong>Filter Hooks:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>tribe_settings_tab_id<\/em>: filters the tab ID<\/li>\n\n\n\n<li><em>tribe_settings_tab_name<\/em>: filter the tab name<\/li>\n\n\n\n<li><em>tribe_settings_tab_{$field_id}<\/em>: filters the specified tab property<\/li>\n\n\n\n<li><em>tribe_settings_do_content_parent_option<\/em>: filters the parent option for a field<\/li>\n\n\n\n<li><em>tribe_settings_field_default<\/em>: filters the default for a field<\/li>\n\n\n\n<li><em>tribe_settings_get_option_value_pre_display<\/em>: filters the value before giving it to the <em>Tribe__Field<\/em> class<\/li>\n<\/ul>\n\n\n\n<p><strong>Default Arguments:<\/strong><\/p>\n\n\n\n<p>Below are the default arguments with an explanation for each, these are passed via <em>$args<\/em>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8216;fields&#8217; =&gt; array(), the fields for the tab<\/li>\n\n\n\n<li>&#8216;priority&#8217; =&gt; 50, the priority of a tab &#8211; this will determine the placement of the tab, see below for a more in-depth explanation<\/li>\n\n\n\n<li>&#8216;show_save&#8217; =&gt; true, whether to show the save button on this tab<\/li>\n\n\n\n<li>&#8216;display_callback&#8217; =&gt; false, a function name to generate the tab&#8217;s content instead of the default behaviour<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-priority\">Priority<\/h3>\n\n\n\n<p>The <em>priority<\/em> argument controls where your tab appears in the row of settings tabs. Internally it&#8217;s passed to the <em>tribe_settings_tabs<\/em> filter by <em>Tribe__Settings_Tab::addTab()<\/em>: <em>add_filter(&#8216;tribe_settings_tabs&#8217;, array($this, &#8216;addTab&#8217;), $priority);<\/em><\/p>\n\n\n\n<p>The Events Calendar&#8217;s tabs use the following priorities, which you can slot around:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>General: 10<\/li>\n\n\n\n<li>Display \/ Template: 20<\/li>\n\n\n\n<li>Defaults (Pro only): 30<\/li>\n\n\n\n<li>Licenses (Pro and add-ons only): 40<\/li>\n\n\n\n<li>Help: 60<\/li>\n<\/ul>\n\n\n\n<p>A priority of 9 would insert your tab right before General; 35 would place it between Defaults and Licenses; 55 would place it between Licenses and Help. If you omit <em>priority<\/em>, it defaults to 50 &#8211; which lands your tab just before Help.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-fields-parent-option-and-default\">Fields: parent_option and default<\/h3>\n\n\n\n<p>The <em>Tribe__Settings_Tab<\/em> class processes 2 extra parameters for fields above and beyond those of <em>Tribe__Field<\/em>: <em>parent_option<\/em>, which controls where the field&#8217;s value is stored, and <em>default<\/em>, which sets a default value if one isn&#8217;t present.<\/p>\n\n\n\n<p><em>parent_option<\/em> has three modes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Omit it<\/strong> (default): the field is saved as a key inside the <em>Tribe__Main::OPTIONNAME<\/em> serialized array &#8211; the same array the rest of The Events Calendar uses. Use this for anything calendar-adjacent so users can back up \/ migrate all your settings alongside ours. Read values back with <em>tribe_get_option( &#8216;your_field_id&#8217; )<\/em>.<\/li>\n\n\n\n<li><strong>Set it to <em>false<\/em><\/strong>: the field is saved as its own stand-alone WordPress option. Use this for sensitive or large values you want to keep out of the main options array (API tokens, long JSON payloads, etc.). Read it back with <em>get_option( &#8216;your_field_id&#8217; )<\/em>.<\/li>\n\n\n\n<li><strong>Set it to a string<\/strong>: the field is saved as a key inside a serialized array under that option name. Use this to group your add-on&#8217;s fields into their own namespaced option (e.g. <em>&#8216;my_addon_options&#8217;<\/em>) while keeping them out of TEC&#8217;s main options array.<\/li>\n<\/ul>\n\n\n\n<p>The <em>Tribe__Main::OPTIONNAME<\/em> constant is what you want. (The older <em>Tribe__Events__Main::OPTIONNAME<\/em> still exists but is deprecated as of TEC 4.0 &#8211; use <em>Tribe__Main::OPTIONNAME<\/em> in new code.)<\/p>\n\n\n\n<p>Setting the <em>default<\/em> parameter is important for options that are required, so that your code has a sensible value to fall back on before the user has ever visited your settings tab.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-complete-example-a-tab-with-validation-and-a-callback\">Complete example: a tab with validation and a callback<\/h2>\n\n\n\n<p>The Quick Start above covered the happy path. The example below shows a few more things you&#8217;re likely to reach for: a mix of field types, a validated URL, a field saved as its own standalone option, and a <em>tribe_settings_save_field_*<\/em> hook to run custom logic when a specific value changes.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_action( &#039;tribe_settings_do_tabs&#039;, function () {\n\t$fields = &#x5B;\n\t\t&#039;my_addon_info&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039; =&gt; &#039;html&#039;,\n\t\t\t&#039;html&#039; =&gt; &#039;&lt;p&gt;&#039; . esc_html__( &#039;Configure how My Add-on connects to your external service.&#039;, &#039;my-addon&#039; ) . &#039;&lt;\/p&gt;&#039;,\n\t\t],\n\t\t&#039;my_addon_endpoint&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039;            =&gt; &#039;text&#039;,\n\t\t\t&#039;label&#039;           =&gt; __( &#039;Service endpoint URL&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;tooltip&#039;         =&gt; __( &#039;Full HTTPS URL of the service you want to sync with.&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;validation_type&#039; =&gt; &#039;url&#039;,\n\t\t\t&#039;default&#039;         =&gt; &#039;https:\/\/api.example.com\/v1&#039;,\n\t\t],\n\t\t&#039;my_addon_api_token&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039;            =&gt; &#039;text&#039;,\n\t\t\t&#039;label&#039;           =&gt; __( &#039;API token&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;parent_option&#039;   =&gt; false, \/\/ Save as a standalone option, outside TEC&#039;s main options array.\n\t\t\t&#039;validation_type&#039; =&gt; &#039;alpha_numeric_with_dashes_and_underscores&#039;,\n\t\t\t&#039;can_be_empty&#039;    =&gt; true,\n\t\t],\n\t\t&#039;my_addon_mode&#039; =&gt; &#x5B;\n\t\t\t&#039;type&#039;            =&gt; &#039;dropdown&#039;,\n\t\t\t&#039;label&#039;           =&gt; __( &#039;Sync mode&#039;, &#039;my-addon&#039; ),\n\t\t\t&#039;options&#039;         =&gt; &#x5B;\n\t\t\t\t&#039;realtime&#039; =&gt; __( &#039;Realtime&#039;, &#039;my-addon&#039; ),\n\t\t\t\t&#039;hourly&#039;   =&gt; __( &#039;Hourly&#039;, &#039;my-addon&#039; ),\n\t\t\t\t&#039;manual&#039;   =&gt; __( &#039;Manual only&#039;, &#039;my-addon&#039; ),\n\t\t\t],\n\t\t\t&#039;validation_type&#039; =&gt; &#039;options&#039;,\n\t\t\t&#039;default&#039;         =&gt; &#039;hourly&#039;,\n\t\t],\n\t];\n\n\tnew Tribe__Settings_Tab(\n\t\t&#039;my-addon&#039;,\n\t\t__( &#039;My Add-on&#039;, &#039;my-addon&#039; ),\n\t\t&#x5B;\n\t\t\t&#039;priority&#039; =&gt; 55,\n\t\t\t&#039;fields&#039;   =&gt; $fields,\n\t\t]\n\t);\n} );\n\n\/\/ React when the sync mode is saved - e.g. reschedule a cron.\nadd_action( &#039;tribe_settings_save_field_my_addon_mode&#039;, function ( $field_id, $value ) {\n\twp_clear_scheduled_hook( &#039;my_addon_sync&#039; );\n\tif ( &#039;hourly&#039; === $value ) {\n\t\twp_schedule_event( time(), &#039;hourly&#039;, &#039;my_addon_sync&#039; );\n\t}\n}, 10, 2 );\n<\/pre><\/div>\n\n\n<p>Things to notice:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Each field declares its own <em>validation_type<\/em>, which Tribe__Validate applies automatically on save. If validation fails, an error is shown in-place on the field and the value is not persisted.<\/li>\n\n\n\n<li><em>my_addon_api_token<\/em> uses <em>&#8216;parent_option&#8217; =&gt; false<\/em> so it saves to the <em>my_addon_api_token<\/em> WordPress option directly, instead of being rolled into the <em>tribe_events_calendar_options<\/em> array.<\/li>\n\n\n\n<li>The <em>tribe_settings_save_field_my_addon_mode<\/em> action is a per-field save hook &#8211; a clean place to react to specific option changes without having to diff the whole options array.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-tips-amp-common-pitfalls\">Tips &amp; common pitfalls<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Always register tabs on <em>tribe_settings_do_tabs<\/em>.<\/strong> Registering earlier (e.g. on <em>init<\/em>) means Tribe__Settings may not be loaded yet; registering later (e.g. <em>admin_menu<\/em>) means your tab won&#8217;t show up.<\/li>\n\n\n\n<li><strong>Prefix your field IDs.<\/strong> Field IDs become keys inside the shared <em>Tribe__Main::OPTIONNAME<\/em> array when you use the default <em>parent_option<\/em>. A prefix (<em>my_addon_<\/em>, <em>acme_<\/em>, etc.) prevents collisions with ours or with another add-on&#8217;s fields.<\/li>\n\n\n\n<li><strong>Reading values back.<\/strong> Use <em>tribe_get_option( $field_id, $default )<\/em> for fields stored under <em>Tribe__Main::OPTIONNAME<\/em>, and <em>get_option( $field_id, $default )<\/em> for standalone options. Always pass a default to guard against the option not existing yet.<\/li>\n\n\n\n<li><strong>Pick a real <em>validation_type<\/em>.<\/strong> Leaving it off, or setting it to <em>&#8216;none&#8217;<\/em>, means the value is saved as-is with no sanitization. Match the validation type to the field type (<em>url<\/em> for URLs, <em>email<\/em> for email, <em>boolean<\/em> for toggles, <em>options<\/em> for dropdowns and radios). Fall back to <em>html<\/em> or <em>textarea<\/em> for free-form content that still needs kses-style sanitization.<\/li>\n\n\n\n<li><strong>Heading fields are cosmetic.<\/strong> <em>heading<\/em> and <em>html<\/em> field types render content but do not save anything &#8211; use them freely to structure your tab into sections.<\/li>\n\n\n\n<li><strong>Use <em>display_callback<\/em> when you need full control.<\/strong> If your tab is mostly custom UI (a setup wizard, a status dashboard, etc.) rather than a list of fields, set <em>&#8216;display_callback&#8217; =&gt; &#8216;your_function&#8217;<\/em> in the tab args to render the tab&#8217;s body yourself.<\/li>\n\n\n\n<li><strong>Turn off Save when it doesn&#8217;t apply.<\/strong> For read-only or informational tabs, pass <em>&#8216;show_save&#8217; =&gt; false<\/em> to suppress the Save Changes button.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-adding-custom-code-to-your-site\">Adding custom code to your site<\/h2>\n\n\n\n<p>You can add these PHP snippets to your theme&#8217;s <code>functions.php<\/code> file, but we recommend using a dedicated code snippets plugin like <strong><a href=\"https:\/\/wordpress.org\/plugins\/code-snippets\/\" target=\"_blank\" rel=\"noreferrer noopener\">Code Snippets<\/a><\/strong> so your changes survive theme updates. For more details, see our guide on the <a href=\"https:\/\/theeventscalendar.com\/knowledgebase\/best-practices-for-implementing-custom-code-snippets\/\">best practices for implementing custom code snippets<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re writing a custom add-on, a site-specific plugin, or a code snippet that extends The Events Calendar or Event Tickets, the Tribe Settings API gives you a clean way to plug your own options into the existing settings screens &#8211; the same API our own tabs (General, Display, Integrations, etc.) are built on. Instead&#8230;<\/p>\n","protected":false},"author":84,"featured_media":1955565,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","_swpsp_post_exclude":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"ep_exclude_from_search":false,"footnotes":""},"categories":[24,345,59,350],"tags":[25],"stellar-product-taxonomy":[155,161],"class_list":["post-1896492","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-customizing","category-developer","category-php","category-settings","tag-customizations","stellar-product-taxonomy-event-tickets","stellar-product-taxonomy-the-events-calendar"],"acf":[],"taxonomy_info":{"category":[{"value":24,"label":"Customizing"},{"value":345,"label":"Developer"},{"value":59,"label":"PHP"},{"value":350,"label":"Settings"}],"post_tag":[{"value":25,"label":"Customizations"}],"stellar-product-taxonomy":[{"value":155,"label":"Event Tickets"},{"value":161,"label":"The Events Calendar"}]},"featured_image_src_large":["https:\/\/images.theeventscalendar.com\/kb\/uploads\/2023\/02\/social-share-1024x538.png",1024,538,true],"author_info":{"display_name":"The Events Calendar Team","author_link":"https:\/\/theeventscalendar.com\/knowledgebase\/author\/the_events_calendar_team\/"},"comment_info":0,"category_info":[{"term_id":24,"name":"Customizing","slug":"customizing","term_group":0,"term_taxonomy_id":24,"taxonomy":"category","description":"","parent":0,"count":67,"filter":"raw","term_order":"0","cat_ID":24,"category_count":67,"category_description":"","cat_name":"Customizing","category_nicename":"customizing","category_parent":0},{"term_id":345,"name":"Developer","slug":"developer","term_group":0,"term_taxonomy_id":345,"taxonomy":"category","description":"","parent":0,"count":9,"filter":"raw","term_order":"0","cat_ID":345,"category_count":9,"category_description":"","cat_name":"Developer","category_nicename":"developer","category_parent":0},{"term_id":59,"name":"PHP","slug":"php","term_group":0,"term_taxonomy_id":59,"taxonomy":"category","description":"","parent":24,"count":52,"filter":"raw","term_order":"0","cat_ID":59,"category_count":52,"category_description":"","cat_name":"PHP","category_nicename":"php","category_parent":24},{"term_id":350,"name":"Settings","slug":"settings","term_group":0,"term_taxonomy_id":350,"taxonomy":"category","description":"","parent":0,"count":15,"filter":"raw","term_order":"0","cat_ID":350,"category_count":15,"category_description":"","cat_name":"Settings","category_nicename":"settings","category_parent":0}],"tag_info":[{"term_id":25,"name":"Customizations","slug":"customizations","term_group":0,"term_taxonomy_id":25,"taxonomy":"post_tag","description":"","parent":0,"count":31,"filter":"raw","term_order":"0"}],"_links":{"self":[{"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/posts\/1896492","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/users\/84"}],"replies":[{"embeddable":true,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/comments?post=1896492"}],"version-history":[{"count":3,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/posts\/1896492\/revisions"}],"predecessor-version":[{"id":1969231,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/posts\/1896492\/revisions\/1969231"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/media\/1955565"}],"wp:attachment":[{"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/media?parent=1896492"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/categories?post=1896492"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/tags?post=1896492"},{"taxonomy":"stellar-product-taxonomy","embeddable":true,"href":"https:\/\/theeventscalendar.com\/knowledgebase\/wp-json\/wp\/v2\/stellar-product-taxonomy?post=1896492"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}