# Frontend Runtime Extension Contract (V1) This document defines the stable frontend runtime integration surface for plugins that extend FrontEdit in the browser. ## Purpose This contract answers four questions for external integrations: 1. How another plugin may open and control FrontEdit editing. 2. What schema-resolved runtime data FrontEdit guarantees to expose. 3. Which lifecycle hooks and events are stable for observing editing and the standard FrontEdit save flow. 4. Which globals and implementation details are explicitly private. ## Scope This contract covers the browser runtime only. It does not define: 1. PHP handler registration. 2. Schema authoring rules. 3. Internal editor-state layout. 4. REST endpoint internals or private save helpers. 5. Internal DOM classes or data attributes unless explicitly documented here. ## Stability Model FrontEdit exposes one stable base namespace for browser integrations: ```js window.MWP.SFE.PublicApi ``` When FrontEdit Pro is active, FrontEdit also exposes one optional pro-only namespace: ```js window.MWP.SFE.ProApi ``` Everything else on `window.MWP.SFE` is private unless this document explicitly says otherwise. ### Two-tier contract This document uses two stability tiers: 1. `V1 committed surface` External plugins may rely on these methods, events, and return shapes. 2. `Candidate APIs under evaluation` These are roadmap items only. They are not part of the stable contract and may change or never ship. ### Versioning The runtime extension contract is versioned independently from the schema contract. `window.MWP.SFE.PublicApi` must expose: ```js SFE.PublicApi.getApiInfo(); ``` Expected shape: ```js { apiVersion: 1, namespace: 'window.MWP.SFE.PublicApi', features: { editorControl: true, runtimeInspection: true, editableBlockDiscovery: true, editingRuntimeResolution: true, publicOperationContracts: true, operations: true, operationPreflight: true, listOperationContracts: true, mediaInspection: true, mediaSessionControl: true, explicitStaging: true, events: true, blockRefresh: true } } ``` Version rules: 1. Additive methods, additive event payload fields, and additive snapshot fields are minor-safe. 2. Removing or renaming methods, changing event semantics, or changing documented return-shape meaning requires an `apiVersion` bump. 3. Private internals may change at any time without notice. ## Public Namespace Rules External plugins may: 1. Call documented `SFE.PublicApi.*` methods. 2. Call documented `SFE.ProApi.*` methods only when the pro plugin is active and the method is documented here as pro-only. 3. Subscribe only to documented `SFE.PublicApi` events. 4. Store and compare documented snapshot data returned by the API. External plugins must not: 1. Monkey-patch FrontEdit methods. 2. Directly mutate `window.MWP.SFE` objects unless a documented API explicitly allows it. 3. Depend on underscore-prefixed properties. 4. Rebuild schema runtime resolution, media descriptor resolution, or block-state hydration from private internals when a public API exists. ## V1 Committed Surface ### Discovery #### Server-side AI discovery When the WordPress Abilities API is available, an authorized FrontEdit editor may call the following post-scoped, read-only abilities: 1. `mwpsfe/list-editable-blocks` with `post_id` to retrieve selectable block UUIDs, block types, edit handler IDs, and source-text summaries. 2. `mwpsfe/get-editable-block` with `post_id` and `uuid` to retrieve focused content for one already-authorized editable block. 3. `mwpsfe/get-public-operation-contract` with `post_id` and `uuid` to retrieve the handler-derived public operation contract and its current public input state for one already-authorized editable block. 4. `mwpsfe/get-frontend-runtime-contract` with `post_id` to retrieve this canonical browser contract. These abilities authorize the current user against the exact requested post; they do not discover WordPress posts/pages, execute browser methods, or create an external save path. WordPress core remains responsible for page discovery. Once the browser runtime is present, integrations must still verify availability through `SFE.PublicApi.getApiInfo()` and use `SFE.PublicApi.getEditableBlocks()` to enumerate the live page. #### Server-side `current_operation_state` `mwpsfe/get-public-operation-contract` returns an immutable `contract` and a separate mutable `current_operation_state` array. Each record is: ```json { "componentId": "content", "operationId": "rewrite_text", "state": { "runs": [] } } ``` The record's `state` object contains only the public inputs declared by that operation. FrontEdit derives these values from the owning handler's schema and current parsed block state; it never publishes attributes, bindings, selectors, or executor metadata. Integrations must use this projection when a generated proposal needs to preserve a current text, media, link, or setting value. They must not reconstruct an equivalent map from raw block attributes. `core/list` keeps its documented browser-owned current-state surface through `SFE.PublicApi.getListStructure(...)` and its operation descriptor through `SFE.PublicApi.getListOperationContract(...)`, because its runtime list-item UUIDs are session-scoped rather than server-side generic operation IDs. #### `getEditableBlocks() -> EditableBlock[]` Return the FrontEdit-editable blocks currently known to the live page runtime. ```js const blocks = SFE.PublicApi.getEditableBlocks(); const match = blocks.find(block => block.contentText.includes('Pricing')); ``` Each entry is a `BlockSnapshot` plus `contentText`, which is normalized text from the current rendered block element. Use its `uuid` with `resolveEditingRuntime(...)` before choosing a documented edit operation. This method is the supported browser discovery path; integrations must not scrape private FrontEdit DOM attributes to enumerate UUIDs. #### Human save handoff An integration may inspect a block, open FrontEdit, and apply documented runtime operations or staging. It must then hand control to the authorized human to review and complete FrontEdit's standard save UI. V1 has no external direct-save API. #### `getApiInfo()` ```js const info = SFE.PublicApi.getApiInfo(); ``` Returns the contract version and feature flags for this runtime. ### Editor Control #### `openEditor(options) -> Promise` Open FrontEdit editing for a target block through the supported runtime path. ```js await SFE.PublicApi.openEditor({ uuid, element, handlerId, componentId, mode: 'edit', source: 'external' }); ``` Rules: 1. `uuid` is required. 2. `element` is optional when the block can be resolved from `uuid`. 3. `handlerId` is optional when FrontEdit can resolve the applicable handler for the block. 4. `componentId` is optional. When supplied, FrontEdit targets the documented editable component for the session. 5. `mode` defaults to `'edit'`. 6. `source` is a caller label for diagnostics and event payloads. Returns an `EditorSnapshot` when FrontEdit opened an editor session, otherwise `null`. #### `closeEditor(options = {}) -> boolean` Close the active editor session through the supported runtime path. ```js SFE.PublicApi.closeEditor({ uuid, restoreOriginal: true, reason: 'api', source: 'external' }); ``` Rules: 1. `uuid` is optional. When omitted, FrontEdit closes the active editor if one exists. 2. `restoreOriginal` defaults to `true`. 3. `reason` is an informational reason token. 4. `source` is a caller label for diagnostics and event payloads. Returns `true` when a close was attempted through the active supported editor session, otherwise `false`. #### `isEditorOpen() -> boolean` Returns whether FrontEdit currently has an active editor session. #### `getActiveEditor() -> EditorSnapshot|null` Returns a stable snapshot of the current active editor session. The return value is a snapshot, not a mutable live internal object. ### Runtime Inspection #### `resolveRuntime(options) -> ResolvedRuntime|null` Resolve the schema-aware runtime view FrontEdit would use for editing. ```js const runtime = SFE.PublicApi.resolveRuntime({ uuid, element, handlerId }); ``` Returns a stable runtime snapshot for the target block or `null` when no supported runtime could be resolved. #### `resolveEditingRuntime(options) -> ResolvedEditingRuntime|null` Resolve the richer schema-driven editing runtime FrontEdit would use for active editing or proposal materialization. ```js const runtime = SFE.PublicApi.resolveEditingRuntime({ uuid, element, handlerId, blockState, attributeChanges }); ``` Returns a detailed editing runtime snapshot with resolved component metadata and live component element references. Rules: 1. `uuid`, `element`, and `handlerId` follow the same resolution rules as `resolveRuntime()`. 2. `blockState` is optional. When supplied, FrontEdit resolves the runtime against that staged block state instead of the current session baseline. 3. `attributeChanges` is optional. When supplied, FrontEdit resolves the runtime against those pending block attribute changes. 4. The returned runtime data is read-only snapshot data except for documented DOM element references inside component entries. #### `getEditOperationContract(options) -> EditOperationContract|null` Return FrontEdit's read-only, schema-derived contract for AI or other generated operation proposals. It is a compact projection of the currently resolved handler components and their `editor.operations`; it does not expose a DOM element, route, save control, nonce, or mutable editor state. ```js const contract = SFE.PublicApi.getEditOperationContract({ uuid, element, handlerId }); ``` ```ts type EditOperationContract = { contractVersion: 1; uuid: string; operations: Array<{ id: string; componentId: string; inputs: Record; values?: Array; allowedRunFormats?: string[]; requiredRunFormatAttributes?: Record; }>; }; ``` Rules: 1. Use this contract to discover the exact operations, allowed values, and required inputs for this live block. Do not infer them from a block name or toolbar label. 2. The contract deliberately excludes attribute paths, selectors, executor kinds, serialization behavior, routes, and mutable editor internals. 3. It is not an authorization or mutation API. Generated proposals remain untrusted and must pass FrontEdit preflight before apply. 4. A handler must explicitly mark an operation `publicOperation: true` before it appears here. FrontEdit does not maintain a second public allowlist or synthesize generic operations from a block type. 5. `allowedRunFormats`, when present for a `rich_text_runs` input, contains the handler-declared format tokens permitted in each returned run. `requiredRunFormatAttributes`, when present, maps a format token to the minimum named values that must be present in that run's `formatAttributes[formatToken]` object. It exposes neither rendering tags, optional format data, selectors, nor mutation details. 6. List editing retains its established UUID-oriented list API. Its legal operation kinds and inputs are exposed separately through `getListOperationContract(...)`; they are not part of this generic generated-proposal envelope. #### `getEditableComponents(options) -> EditableComponent[]` Returns the runtime-editable components for the resolved block. #### `getDefaultComponent(options) -> EditableComponent|null` Returns the default editable component for the resolved block, if one exists. ### Public Operation Runtime V1 uses one attribute-free public operation envelope: ```js const operations = [ { id: operation.id, componentId: operation.componentId, inputs: { /* only values declared by getEditOperationContract() */ } } ]; const preflight = SFE.PublicApi.preflightOperations({ uuid, operations }); if (preflight?.valid === true) { SFE.PublicApi.applyOperations({ uuid, operations }); } ``` #### `preflightOperations(options) -> OperationPreflightResult|null` Validate an opaque operation batch against an already open editor without mutating DOM, history, preview state, or saved content. ```ts type OperationPreflightResult = { uuid: string; valid: boolean; validatedOperationIds: string[]; errors: Array<{ code: string; id?: string; componentId?: string }>; }; ``` #### `applyOperations(options) -> OperationResult|null` Stage the same preflighted opaque batch through FrontEdit's shared schema executor. FrontEdit resolves the operation locally from the active handler, performs normal preview and history work, and leaves review, save, and cancel under its normal editor lifecycle. Rules: 1. Call `openEditor(...)` explicitly before preflight or apply. 2. Each operation must exactly match a declaration from `getEditOperationContract(...)`. 3. Callers must not send `kind`, `attribute`, `attributes`, `bindingSource`, DOM selectors, or serialization metadata. 4. Callers processing generated or untrusted content must require `valid === true` before apply. 5. This is a staging API, never a direct-save API. `applyOperations(...)` returns `appliedOperationCount` in addition to its operation ID summary. Integrations that generate a batch must treat the stage as failed unless that count equals the requested operation count. ### V1 Operation Recipes All non-list mutations use the schema-derived operation envelope. Discover the operation on the live block, open that block's editor, preflight the exact batch, then apply the same batch. FrontEdit owns the resulting preview, history, review, cancel, and save lifecycle. #### Operation Envelope ```js const contract = SFE.PublicApi.getEditOperationContract({ uuid, element, handlerId }); if (!contract) { throw new Error('No edit-operation contract is available for this block.'); } const getOperation = predicate => { const operation = contract.operations.find(predicate); if (!operation) { throw new Error('The requested operation is not supported by this block.'); } return operation; }; const stage = async operations => { const preflight = SFE.PublicApi.preflightOperations({ uuid, operations }); if ( preflight?.valid !== true || preflight.validatedOperationIds.length !== operations.length ) { throw new Error('FrontEdit rejected the operation batch.'); } const result = SFE.PublicApi.applyOperations({ uuid, operations }); if (result?.appliedOperationCount !== operations.length) { throw new Error('FrontEdit did not stage every operation.'); } return result; }; ``` Every generic operation has exactly this shape: ```js { id: operation.id, componentId: operation.componentId, inputs: { // Exactly the declared input names and values for this operation. } } ``` Use the operation's `inputs` map as the complete field contract. Include every required input, omit optional inputs you do not need, and do not send `kind`, attribute paths, selectors, binding metadata, or other internal fields. #### Text Replacement Find an operation that declares a `rich_text_runs` input and submit the complete replacement run sequence for that component: ```js const rewrite = getOperation(operation => ( operation.componentId === 'content' && operation.inputs.runs?.type === 'rich_text_runs' )); await SFE.PublicApi.openEditor({ uuid, element, handlerId, componentId: rewrite.componentId }); await stage([{ id: rewrite.id, componentId: rewrite.componentId, inputs: { runs: [ { text: 'Updated copy', formats: [], formatAttributes: {} } ] } }]); ``` Use only `allowedRunFormats` exposed by that operation. When `requiredRunFormatAttributes` declares values for a format, include them in the matching run's `formatAttributes` object. #### Scalar Block Setting Settings such as alignment or heading level are schema operations with a declared scalar input. The concrete ID, component, allowed values, and any additional inputs come from the resolved contract: ```js const alignment = getOperation(operation => ( operation.componentId === 'content' && operation.inputs.value?.type === 'scalar' && Array.isArray(operation.values) && operation.values.includes('center') )); await SFE.PublicApi.openEditor({ uuid, element, handlerId, componentId: alignment.componentId }); await stage([{ id: alignment.id, componentId: alignment.componentId, inputs: { value: 'center' } }]); ``` If the declared operation has additional required inputs, include those exact fields in `inputs`. For example, a column-scoped setting can require a `columns` input in addition to `value`. #### Host Link Update For an anchor-host component, select the operation that declares the URL input and provide its declared optional link settings only when needed: ```js const link = getOperation(operation => ( operation.componentId === 'label' && operation.inputs.href?.type === 'url' )); await SFE.PublicApi.openEditor({ uuid, element, handlerId, componentId: link.componentId }); await stage([{ id: link.id, componentId: link.componentId, inputs: { href: 'https://example.com/pricing', new_tab: true } }]); ``` #### Media URL Replacement When the live operation contract declares a URL input for a media component, stage the URL as a generic operation. The operation ID remains contract-owned: ```js const media = getOperation(operation => ( operation.componentId === 'image' && operation.inputs.url?.type === 'url' )); await SFE.PublicApi.openEditor({ uuid, element, handlerId, componentId: media.componentId }); await stage([{ id: media.id, componentId: media.componentId, inputs: { url: 'https://example.com/uploads/updated-image.jpg', source: 'input' } }]); ``` Include `attachmentId` only when the media source provides one. When the contract declares `source`, use `library` for a WordPress media-library item or `input` for a direct URL. For a selected WordPress media-library or upload item, use the documented [`applyActiveMediaSelection(options)`](#applyactivemediaselectionoptions---editorsnapshotnull) method in [Media Inspection And Session Control](#media-inspection-and-session-control). That method's reference includes its required active-session setup and exact request shape. ### List Runtime V1 retains the public list-tree runtime for `core/list`-style blocks that are edited as one root block while exposing nested item/list structure to external callers. #### `getListStructure(options) -> ListNode|null` Return the current live structural snapshot for one open or discoverable list block. ```js const structure = SFE.PublicApi.getListStructure({ uuid, element }); ``` Rules: 1. `uuid` is required unless `element` can be resolved to a block UUID. 2. The target block must resolve to a live `UL` or `OL` root. 3. The return value is a read-only structural snapshot of the live DOM tree. #### `getListOperationContract(options) -> ListOperationContract|null` Return the FrontEdit-owned, read-only operation descriptor for one live list root. This is the machine-readable source of truth for public list operation kinds and their exact input fields. Integrations must use it rather than maintaining a separate list-operation catalog. ```js const contract = SFE.PublicApi.getListOperationContract({ uuid, element }); ``` ```ts type ListOperationContract = { contractVersion: 1; uuid: string; operations: Array<{ kind: string; inputs: Record; }>; }; ``` Rules: 1. `uuid` is required unless `element` can be resolved to a block UUID. 2. The target must resolve to a live `UL` or `OL` root. 3. Each `inputs` map is exact: callers must not add an input not declared for that operation. 4. `existing_list_item_uuid` accepts an item UUID from the current `getListStructure(...)` result. `new_list_item_uuid` is a fresh caller-owned item UUID for an insertion. `direct_list_item_html` is direct item text HTML and must not contain `li`, `ul`, or `ol` wrappers. 5. This is an inspection API, not mutation authority. Callers still must use `preflightListOperations(...)` successfully before `applyListOperations(...)`. #### `applyListOperations(options) -> ListOperationResult|null` Apply one or more structural list mutations as one runtime batch. #### `preflightListOperations(options) -> ListOperationPreflightResult|null` Validate a UUID-oriented list batch against the open FrontEdit list editor without mutating it. ```js const preflight = SFE.PublicApi.preflightListOperations({ uuid, operations }); if (preflight?.valid === true) { SFE.PublicApi.applyListOperations({ uuid, operations }); } ``` Return shape: ```ts type ListOperationPreflightResult = { uuid: string; valid: boolean; validatedOperationKinds: string[]; errors: Array<{ code: string; index?: number }>; }; ``` `insert_child` validates its supplied insertion command during preflight. Its internal follow-up indent is resolved only during the subsequent FrontEdit apply because the new runtime item does not exist until that point. ```js const result = SFE.PublicApi.applyListOperations({ uuid, operations: [ { kind: 'update_list_item_text', itemUuid: '7db1a4ff-8e25-4f7d-a806-9328d473bb96', contentHtml: 'Alpha' }, { kind: 'toggle_list_type', itemUuid: '7db1a4ff-8e25-4f7d-a806-9328d473bb96', } ] }); ``` Rules: 1. `uuid` is required. 2. The target list editor must already be open. 3. `operations` are applied in order against the live mutated tree. 4. Every operation must supply the correct documented UUID target token family for its kind. 5. FrontEdit resolves each operation's runtime UUIDs against the current post-mutation tree immediately before that operation runs. 6. Public callers must use only operation kinds and exact inputs advertised by `getListOperationContract(...)`. 7. Some public operations may expand into multiple internal primitive mutations. For example, `insert_child` inserts the new item after the parent item, then indents it so the tracker creates the nested child list through the normal editor path. 8. Successful batches return one updated list structure snapshot. #### Current V1 list operation descriptor The contract currently advertises: 1. `update_list_item_text` 2. `insert_before` 3. `insert_after` 4. `insert_child` 5. `remove_list_item` 6. `move_before` 7. `move_after` 8. `indent_list_item` 9. `outdent_list_item` 10. `toggle_list_type` These are the public API kinds only. Internally FrontEdit still executes lower-level primitive list operations such as `insert_list_item`, `move_list_item`, and `toggle_list_type`, but only the descriptor returned by `getListOperationContract(...)` is the machine-readable runtime contract. #### List operation payloads | Kind | Required fields | Optional fields | Description | | --- | --- | --- | --- | | `update_list_item_text` | `kind`, `itemUuid`, `contentHtml` | -- | Replaces the direct text HTML for one existing list item. | | `insert_before` | `kind`, `newItemUuid`, `targetItemUuid`, `contentHtml` | -- | Inserts a new sibling item before the target item. | | `insert_after` | `kind`, `newItemUuid`, `targetItemUuid`, `contentHtml` | -- | Inserts a new sibling item after the target item. | | `insert_child` | `kind`, `newItemUuid`, `targetItemUuid`, `contentHtml` | -- | Creates a new child item under the target item. | | `remove_list_item` | `kind`, `itemUuid` | -- | Removes one existing list item and its nested children. | | `move_before` | `kind`, `itemUuid`, `targetItemUuid` | -- | Moves an existing item before the target item. | | `move_after` | `kind`, `itemUuid`, `targetItemUuid` | -- | Moves an existing item after the target item. | | `indent_list_item` | `kind`, `itemUuid` | -- | Indents one existing item through the normal editor list behavior. | | `outdent_list_item` | `kind`, `itemUuid` | -- | Outdents one existing item through the normal editor list behavior. | | `toggle_list_type` | `kind`, `itemUuid` | -- | Toggles the containing list for the referenced item between ordered and unordered. | `contentHtml` is required for operations that create or replace item content. It represents the direct item text HTML only. It must not include wrapping `
  • `, `
      `, or `
        ` elements. Consumers must derive whether an operation carries content from its `direct_list_item_html` input descriptor, not from a copied operation-kind allowlist. #### Public target-token rules Public list operations must use only the documented runtime UUID token family for their kind. FrontEdit rejects public operations that omit the required token. 1. `update_list_item_text`, `remove_list_item`, `indent_list_item`, and `outdent_list_item` target one existing list item and must provide `itemUuid`. 2. `insert_before` and `insert_after` must provide `newItemUuid` plus `targetItemUuid`. 3. `insert_child` must provide `newItemUuid` plus `targetItemUuid`. If the target item does not already own a child list, FrontEdit creates the required nested list automatically. 4. `move_before` and `move_after` must provide `itemUuid` plus `targetItemUuid`. 5. `toggle_list_type` must provide `itemUuid`. FrontEdit resolves that item to its current containing list immediately before the toggle runs. 6. Public callers must use only the documented camelCase keys above. Any other keys are outside the API contract. 7. Public callers must not rely on cursor or selection state. Cursor-based inference is reserved for internal editor-originated calls only. #### Runtime UUID ownership List-item UUIDs and list-node UUIDs have different ownership rules. 1. Public callers are responsible for generating UUIDs for newly created list items. 2. FrontEdit is responsible for generating and managing UUIDs for list nodes. 3. Public callers must not create, assign, or mutate list-node UUIDs directly. 4. When a structural operation creates a new nested list, FrontEdit assigns the resulting `listUuid`. 5. Public list operations target items, not list nodes, even though returned structure snapshots still expose `listUuid` values. #### Recommended UUID convention FrontEdit does not enforce a specific caller UUID format for public list operations. Recommended convention: 1. Use RFC 4122 version 4 UUID strings for `itemUuid`, `targetItemUuid`, and `newItemUuid`. 2. Generate one fresh UUID for every new list item the caller intends to create. 3. Treat runtime UUIDs as session-scoped cursor tokens only. Do not persist or reuse them after the list editor closes or the page reloads. #### `ListNode` `getListStructure()` and successful list-operation results return recursive list nodes plus item nodes so child lists remain distinct from the list items that own them. A list node contains: 1. `listUuid` (string): session-scoped runtime UUID for this list node 2. `listPath` (string): empty string for the root list, or the parent item path that owns this nested child list 3. `ordered` (boolean): whether this specific list node is `OL` 4. `items` (array): direct child list items for this list node Each item contains: 1. `itemUuid` (string): session-scoped runtime UUID for this item 2. `path` (string): item tree path 3. `pathLabel` (string): human-readable 1-based path label 4. `depth` (number): zero-based nesting depth 5. `contentHtml` (string): direct item text HTML only 6. `childList` (`ListNode|null`): nested list node owned by this item, or `null` Example: ```json { "listUuid": "e183f2b5-2f90-4ca2-8ea8-c3d8c72ab2c1", "listPath": "", "ordered": false, "items": [ { "itemUuid": "7db1a4ff-8e25-4f7d-a806-9328d473bb96", "path": "0", "pathLabel": "1", "depth": 0, "contentHtml": "a", "childList": { "listUuid": "fd818143-75d8-4ae9-8f3f-798d54150472", "listPath": "0", "ordered": false, "items": [ { "itemUuid": "c71fad00-2d1f-4f70-b0fc-84681f5ef8a0", "path": "0_0", "pathLabel": "1.1", "depth": 1, "contentHtml": "b", "childList": { "listUuid": "2cd9f476-1d91-45e5-bd0b-ae981b78a111", "listPath": "0_0", "ordered": false, "items": [ { "itemUuid": "b2f4ffad-edbc-48e9-950d-2716b5bf6942", "path": "0_0_0", "pathLabel": "1.1.1", "depth": 2, "contentHtml": "c", "childList": null } ] } } ] } } ] } ``` #### `ListOperationResult` Successful list runtime mutations return: 1. `uuid` (string): target block UUID 2. `operationsApplied` (array of strings): normalized operation kinds applied in order 3. `structure` (`ListNode`): updated live list structure snapshot ### Media Inspection And Session Control #### `getMediaContext(options) -> MediaContext|null` Resolve the media-editable context for a block or specific component. ```js const mediaContext = SFE.PublicApi.getMediaContext({ uuid, element, handlerId, componentId }); ``` Returns `null` when the target block is not media-editable through the documented runtime surface. #### `getMediaDescriptor(options) -> MediaDescriptor|null` Returns the stable media descriptor for the selected file component, if one exists. #### `isMediaEditable(options) -> boolean` Returns whether the resolved block exposes a file-editable component through the public runtime contract. #### `applyActiveMediaSelection(options) -> EditorSnapshot|null` Apply one selected media item to the current active schema-media editor session through FrontEdit's supported runtime path. ```js const editor = SFE.PublicApi.applyActiveMediaSelection({ uuid, url, attachmentId, source: 'library' }); ``` Rules: 1. `uuid` is required and must match the current active editor session. 2. `url` is required. 3. `attachmentId` is optional. 4. `source` may be `'library'` or `'input'` and defaults to the input-style save transition when omitted. 5. Returns an updated `EditorSnapshot` when the active media session accepted the selection, otherwise `null`. ### Explicit Staging V1 supports explicit block-state staging only. Staging is editor preparation, not external save execution. External plugins may stage block state and open or guide the FrontEdit editor, but the user must complete saving through FrontEdit's standard save UI and normal FrontEdit save workflow. #### `stageBlockState(stage) -> void` Stage a temporary block-state payload for one block so that subsequent editor open and hydration flows may consume it through FrontEdit's supported staging path. ```js SFE.PublicApi.stageBlockState({ uuid, handlerId, blockState, source: 'external' }); ``` Rules: 1. `uuid` is required. 2. `handlerId` is optional metadata for the caller and diagnostics. 3. `blockState` must match the shape FrontEdit's canonical block hydration path expects. 4. Staged block state is temporary and applies only through the documented FrontEdit runtime path. 5. Staged changes do not create a supported external save path in V1. #### `clearStagedBlockState(uuid) -> void` Clear any currently staged block state for the given block UUID. ### Session Utilities #### `on(eventName, handler) -> unsubscribeFn` Subscribe to one documented runtime event. ```js const unsubscribe = SFE.PublicApi.on('save:after', payload => { // observe successful save completion }); ``` Returns an unsubscribe function equivalent to calling `off(eventName, handler)`. #### `off(eventName, handler) -> void` Remove a previously registered event handler. #### `refreshBlock(uuid, options?) -> Promise` Request that FrontEdit refresh the live DOM for one block through its supported refresh path and return the resulting `BlockSnapshot`. ### Dirty State, Page Context, and Lookup Utilities #### `getDirtyBlocks() -> DirtyBlock[]` Returns a stable summary of the blocks that currently have unsaved changes in the active runtime session. #### `hasDirtyBlocks() -> boolean` Returns whether any block currently has unsaved changes. #### `isBatchSessionActive() -> boolean` Returns whether FrontEdit currently has an active batch-edit session. #### `resetDirtyBlocks(uuids, options?) -> boolean` Reset the tracked dirty batch state for the supplied block UUIDs back to the current batch-session baseline. ### Pro-only Session Utilities These methods exist only when FrontEdit Pro is active on the page. #### `ensureBatchSession() -> Promise` Ensure the shared batch-edit session exists before downstream runtime checks or mutations depend on it. ```js const ready = await SFE.ProApi.ensureBatchSession(); ``` Rules: 1. This method is available only on `window.MWP.SFE.ProApi`. 2. It returns `false` when batch editing is unavailable or disabled for the current page. 3. It may be called repeatedly; repeated calls are safe and reuse any in-flight session bootstrap work. #### `getPageContext() -> PageContext` Returns a stable page-level runtime snapshot. #### `getRestContext() -> RestContext` Returns the REST context FrontEdit guarantees to expose for supported runtime integrations. #### `setRestNonce(nonce) -> RestContext` Update the REST nonce FrontEdit should use for subsequent supported runtime requests on the current page. ```js const restContext = SFE.PublicApi.setRestNonce(refreshedNonce); ``` Rules: 1. `nonce` must be a non-empty string. 2. This updates only the current page runtime state. It does not fetch or mint a new nonce on its own. 3. Callers should use this after their own authenticated nonce-refresh flow succeeds. 4. The return value is the updated `RestContext`. #### `getElementByUuid(uuid) -> Element|null` Returns the current live DOM element for a block UUID, if present. #### `getUuidForElement(element) -> string` Returns the FrontEdit block UUID for the supplied element, or an empty string when none is available. #### `getBlockSnapshot(uuid) -> BlockSnapshot|null` Returns a stable summary snapshot for one block UUID. #### `getEditableBlocks() -> EditableBlock[]` Returns the stable live-page discovery snapshots described above. ## Stable Snapshot Shapes Snapshots are plain data contracts. They are not live editor-state objects and must not be mutated to control FrontEdit. ### `EditorSnapshot` ```json { "uuid": "8d63...", "handlerId": "core_image", "mode": "edit", "blockName": "core/image", "componentType": "file", "componentId": "image", "saveStrategy": "single", "hasMediaSession": true, "isDirty": false, "isDraftSession": false, "isBatchSession": false } ``` Required fields: 1. `uuid` 2. `handlerId` 3. `mode` 4. `blockName` 5. `componentType` 6. `componentId` 7. `saveStrategy` 8. `hasMediaSession` 9. `isDirty` 10. `isDraftSession` 11. `isBatchSession` Field notes: 1. `hasMediaSession` is `true` when the active editor host currently exposes the supported media-selection control surface used by `SFE.PublicApi.applyActiveMediaSelection(...)`. ### `ResolvedRuntime` ```json { "uuid": "8d63...", "handlerId": "core_cover", "blockName": "core/cover", "schemaVersion": 1, "mode": "mixed", "defaultComponentId": "image", "components": [] } ``` Required fields: 1. `uuid` 2. `handlerId` 3. `blockName` 4. `schemaVersion` 5. `mode` 6. `defaultComponentId` 7. `components` ### `EditableComponent` ```json { "id": "image", "label": "Image", "type": "file", "selector": "figure", "default": true, "target": { "selector": "img", "attribute": "src", "mediaType": "image" }, "mediaDescriptor": { "componentId": "image", "scopeSelector": "figure", "targetSelector": "img", "attribute": "src", "mediaType": "image" } } ``` Required fields: 1. `id` 2. `label` 3. `type` 4. `selector` 5. `default` Optional fields: 1. `required` 2. `placeholder` 3. `target` 4. `mediaDescriptor` 5. `editor` ### `MediaDescriptor` ```json { "componentId": "image", "scopeSelector": "figure", "targetSelector": "img", "attribute": "src", "mediaType": "image" } ``` Required fields: 1. `componentId` 2. `scopeSelector` 3. `targetSelector` 4. `attribute` 5. `mediaType` ### `MediaContext` ```json { "supported": true, "componentId": "image", "mediaType": "image", "accept": "image/*", "label": "image block", "descriptor": { "componentId": "image", "scopeSelector": "figure", "targetSelector": "img", "attribute": "src", "mediaType": "image" } } ``` Required fields: 1. `supported` 2. `componentId` 3. `mediaType` 4. `accept` 5. `label` 6. `descriptor` ### `DirtyBlock` ```json { "uuid": "8d63...", "handlerId": "core_paragraph", "blockName": "core/paragraph", "beforeRaw": "

        Old

        ", "afterRaw": "

        New

        " } ``` Required fields: 1. `uuid` 2. `handlerId` 3. `blockName` 4. `beforeRaw` 5. `afterRaw` ### `PageContext` ```json { "postId": 123, "permissions": { "can_publish": true, "can_draft": false, "can_comment": true, "can_batch": true }, "hasDraftPreview": false, "isEditorOpen": false, "activeMode": "" } ``` Required fields: 1. `postId` 2. `permissions` 3. `hasDraftPreview` 4. `isEditorOpen` 5. `activeMode` ### `RestContext` ```json { "baseUrl": "https://example.com/wp-json/", "namespaceUrl": "https://example.com/wp-json/mwpsfe/v1/", "nonce": "..." } ``` Required fields: 1. `baseUrl` 2. `namespaceUrl` 3. `nonce` ### `BlockSnapshot` ```json { "uuid": "8d63...", "blockName": "core/image", "handlerIds": ["core_image", "core_image_comment"], "isPending": false, "pendingInfo": null, "elementPresent": true } ``` Required fields: 1. `uuid` 2. `blockName` 3. `handlerIds` 4. `isPending` 5. `pendingInfo` 6. `elementPresent` ### `EditableBlock` An `EditableBlock` contains every `BlockSnapshot` field plus: ```json { "contentText": "Visible normalized text from this block" } ``` `contentText` is the current rendered text used for live-page matching. It is not serialized Gutenberg block markup and must not be used as a write payload. ## Stable Events V1 events are observable only. They provide visibility into FrontEdit runtime lifecycle. They are not interception points and do not allow cancellation, mutation, or alternate control flow through event payload side effects. ### Subscription rules 1. Consumers may subscribe only through `SFE.PublicApi.on()`. 2. Consumers must treat event payloads as snapshots. 3. Event payload objects must not be mutated. ### `editor:opened` Fires after FrontEdit has opened an editor session through a supported path. Payload: ```json { "source": "external", "editor": {} } ``` Required fields: 1. `source` 2. `editor` as `EditorSnapshot` ### `editor:beforeClose` Fires before FrontEdit closes an editor session through a supported path. Payload: ```json { "source": "api", "reason": "api", "editor": {} } ``` Required fields: 1. `source` 2. `reason` 3. `editor` as `EditorSnapshot` ### `editor:closed` Fires after FrontEdit closes an editor session through a supported path. Payload: ```json { "source": "api", "reason": "api", "editor": {} } ``` Required fields: 1. `source` 2. `reason` 3. `editor` as `EditorSnapshot` ### `editor:componentChanged` Fires when FrontEdit changes the active editable component within one editor session. Payload: ```json { "source": "sfe", "editor": {} } ``` Required fields: 1. `source` 2. `editor` as `EditorSnapshot` ### `save:before` Fires when FrontEdit is about to begin a supported save path. Payload: ```json { "source": "sfe", "editor": {}, "saveStrategy": "single" } ``` Required fields: 1. `source` 2. `editor` as `EditorSnapshot` 3. `saveStrategy` ### `save:after` Fires after FrontEdit completes a supported save path successfully. Payload: ```json { "source": "sfe", "editor": {}, "saveStrategy": "single", "success": true } ``` Required fields: 1. `source` 2. `editor` as `EditorSnapshot` 3. `saveStrategy` 4. `success` ### `save:error` Fires when FrontEdit's supported save path fails. Payload: ```json { "source": "sfe", "editor": {}, "saveStrategy": "single", "message": "REVISION_CONFLICT" } ``` Required fields: 1. `source` 2. `editor` as `EditorSnapshot` 3. `saveStrategy` 4. `message` ### `block:staged` Fires after `stageBlockState()` records a staged block-state payload. Payload: ```json { "source": "external", "uuid": "8d63...", "handlerId": "core_image" } ``` Required fields: 1. `source` 2. `uuid` 3. `handlerId` ### `block:stageCleared` Fires after `clearStagedBlockState()` clears a staged block-state payload. Payload: ```json { "source": "external", "uuid": "8d63..." } ``` Required fields: 1. `source` 2. `uuid` ### `block:refreshed` Fires after FrontEdit refreshes a block's live DOM through the supported refresh path. Payload: ```json { "source": "sfe", "block": {} } ``` Required fields: 1. `source` 2. `block` as `BlockSnapshot` ## Candidate APIs Under Evaluation The following APIs are not part of V1 and are intentionally non-contractual in this document: 1. `consumeMediaSelection()` 2. `getActiveMediaSession()` 3. `registerBlockStateProvider()` 4. `unregisterBlockStateProvider()` These remain candidate APIs under evaluation so FrontEdit can improve its internal runtime boundaries before committing to stable provider or live media-session semantics. ## Private Runtime Boundary The following names and object families are explicitly private and unsupported for external integrations: 1. `SFE.Context` 2. `SFE.ManagerData` 3. `SFE.SchemaRuntime` 4. `SFE.MediaHelper` 5. `SFE.Api` 6. `SFE.SaveHelpers` 7. `SFE.SaveHooks` 8. `SFE.BlockSerializer` 9. `SFE.BatchEditManager` 10. `SFE.ResolveBlockState` 11. `SFE.ResolveEditorStrategy` 12. Raw `handler.client_config` 13. Raw editor-state objects 14. Underscore-prefixed properties such as `_mwpSchemaRuntime` and `_mwpSchemaMediaSession` 15. Undocumented DOM classes and data attributes Private APIs may change without a public contract version notice. ## Extension Rules External runtime integrations must follow these rules: 1. Use `window.MWP.SFE.PublicApi` as the only supported JS entry point. 2. Use FrontEdit runtime inspection APIs instead of re-resolving schema handlers or media descriptors from private state. 3. Use explicit staging APIs instead of overriding global block-state resolvers. 4. Use documented lifecycle events instead of patching editor open or close methods. 5. Use stable snapshots only for observation and coordination, never for direct mutation of live FrontEdit state. 6. Preserve FrontEdit's canonical save pipeline and do not bypass block serialization rules. 7. Do not treat V1 as a supported direct-save API; saving remains user-driven through standard FrontEdit controls. 8. When an integration refreshes the shared REST nonce during a long-lived session, it should synchronize FrontEdit through `SFE.PublicApi.setRestNonce(...)` instead of mutating `SFE.ManagerData` directly. Feeding Tips for Small Dogs: Secret Hacks Exposed 2026 | PetEatWell

        Feeding Tips for Small Dogs: Secret Hacks Exposed

        Small dogs face unique feeding challenges that bigger breeds don’t have to worry about. Small dogs need smaller, more frequent meals because their tiny stomachs can’t hold much food, yet their fast metabolisms require steady energy throughout the day. Getting their nutrition right isn’t just about portion size – it’s about timing, food choices, and avoiding mistakes that could seriously harm your petite pup.

        Feeding Tips for Small Dogs

        I’ve seen too many small dog owners struggle with feeding routines that work for larger breeds but leave their little companions hungry, overfed, or dealing with blood sugar crashes. Your Chihuahua’s needs are completely different from a Golden Retriever’s, and the size of food bowls can actually affect how much owners feed their dogs.

        You’re about to discover the exact feeding strategies that keep small dogs healthy, satisfied, and thriving. From meal timing to portion control, I’ll walk you through everything you need to know to become your tiny dog’s nutrition hero.

        Feeding Tips for Small Dogs – Key Takeaways

        • Small dogs require multiple small meals throughout the day rather than one or two large feedings
        • Proper portion control and food bowl size are crucial for preventing overfeeding in small breeds
        • Creating a consistent feeding routine helps prevent common health issues like hypoglycemia and digestive problems

        Why Small Dogs Need Special Feeding Tips

        A small dog sitting by a feeding bowl while a person offers food in a cozy kitchen setting.

        Small breed dogs face unique challenges that make standard feeding advice potentially harmful to their health and wellbeing. Their faster metabolisms, smaller stomachs, and increased risk of hypoglycemia require specialized nutrition approaches that differ significantly from what works for larger dogs.

        Small Breed Dog Nutrition Explained

        I’ve seen too many small dog owners struggle with feeding advice that just doesn’t work for their tiny companions. Here’s the reality: small dogs have very special needs in many areas and nutrition tops that list.

        Small breed dogs need higher calorie density in their food. A Chihuahua weighing 4 pounds needs about 200 calories per day, while a 70-pound Golden Retriever needs around 1,200 calories. That might seem obvious, but here’s the kicker: the small dog needs 50 calories per pound compared to just 17 calories per pound for the larger dog.

        Their tiny stomachs can’t hold large volumes of food. This means every bite must pack maximum nutritional value. Low-quality fillers that might be okay for big dogs can leave small dogs malnourished.

        Key nutritional differences for small dogs:

        • Higher fat content (12-18% vs 8-12% for large breeds)
        • Smaller kibble size for easier chewing
        • More frequent feeding schedules
        • Enhanced vitamin and mineral concentrations

        The Unique Metabolism of Small Dogs

        Think of small dogs as tiny furnaces that burn fuel incredibly fast. Their metabolic rate runs twice as high per pound compared to large breeds. This isn’t just about being active – it’s basic biology.

        Small dogs lose body heat much faster through their skin. They’re constantly working to maintain their body temperature, which burns calories at an alarming rate. I’ve watched a 3-pound Yorkie shiver after just 10 minutes outside in 60-degree weather.

        Blood sugar crashes happen quickly in small breeds. While a Lab might go 12 hours between meals without issues, a Maltese can develop dangerous hypoglycemia in just 4-6 hours without food. Their liver stores less glucose, and their small muscle mass can’t provide backup energy.

        Different breeds may be at risk for specific diseases and feeding schedules directly impact these risks. Small dogs need 3-4 small meals daily instead of 1-2 large ones.

        Their digestive systems process food faster too. What takes 24 hours to digest in a German Shepherd might only take 12-16 hours in a Pomeranian.

        Risks of Generic Feeding Advice

        Generic dog feeding charts can be dangerous for small breeds. I’ve seen owners follow package directions meant for “average” 20-30 pound dogs, leading to serious health problems in their 5-pound companions.

        Portion control becomes critical with small dogs. The size of food bowl and scoop affects amount of food owners feed their dogs, and overfeeding a small dog by just 1/4 cup daily can cause obesity within months.

        Standard feeding advice often ignores the choking hazards small dogs face. Regular-sized kibble designed for medium dogs can block a toy breed’s airway. Generic treats meant for all dogs might contain a full day’s calories for a tiny breed in just one piece.

        Timing becomes everything with feeding small dogs. While generic advice suggests twice-daily feeding, small breeds risk hypoglycemic seizures with such long gaps between meals. Their bodies simply can’t store enough energy reserves.

        Many commercial dog foods focus on average-sized dogs, leaving small breeds undernourished or struggling with digestive issues from inappropriate formulations.

        Building the Perfect Meal for Your Small Pup

        A small dog sits near a kitchen counter where a nutritious meal with chicken, vegetables, and grains is being prepared.

        Small breed dogs need more than just smaller portions of regular dog food. Their faster metabolisms and unique body structures require specific nutrients in precise amounts, and even the kibble size can make or break mealtime success.

        Key Nutrients Every Small Dog Needs

        Let’s be real — your tiny pup burns calories like a Ferrari burns gas. Small dogs have metabolisms that run 25% faster than large breeds.

        This means they need more protein per pound of body weight. I recommend looking for foods with at least 25-30% protein content.

        Essential nutrients for small breeds:

        • High-quality protein (chicken, fish, lamb)
        • Healthy fats for energy and coat health
        • DHA for brain development in puppies
        • Calcium and phosphorus in proper ratios

        Small dogs also get cold easily. Their tiny bodies lose heat faster than bigger dogs. That’s why they need more fat in their diet — around 15-20% minimum.

        Don’t forget about nutrient requirements that support strong bones. Small breeds are prone to luxating patella and other joint issues.

        Portion Control: How Much Is Really Enough?

        Here’s the kicker — most small dog owners overfeed their pups. I see it all the time. Those puppy dog eyes are hard to resist!

        Small dogs need only 1/4 to 1 cup of food per day, split into 2-3 meals. But this varies based on:

        Factors affecting portion size:

        • Age (puppies need more frequent meals)
        • Activity level
        • Metabolism speed
        • Health conditions

        Daily feeding guide by weight:

        • 2-5 lbs: 1/4 to 1/2 cup
        • 5-10 lbs: 1/2 to 3/4 cup
        • 10-20 lbs: 3/4 to 1 cup

        I always tell owners to feed their small dogs 3 times daily rather than twice. Their tiny stomachs can’t handle large meals. Plus, it prevents dangerous blood sugar drops.

        Watch your pup’s waist. You should feel their ribs easily but not see them clearly.

        The Kibble Conundrum: Size and Texture

        Ever watched your Chihuahua struggle with kibble meant for a German Shepherd? It’s not cute — it’s actually dangerous.

        Small breed dogs need kibble that’s 8-12mm in size. Anything bigger becomes a choking hazard or gets swallowed whole.

        Why kibble size matters:

        • Prevents choking
        • Encourages proper chewing
        • Aids digestion
        • Reduces gulping and bloat

        The texture should be softer too. Many small dogs benefit from puppy-friendly feeding techniques even as adults.

        Look for triangular or round shapes. Avoid large, hard squares that can get stuck in tiny throats.

        Some small dogs do better with wet food mixed in. It adds moisture and makes the meal more appealing to picky eaters.

        Creating a Smart Feeding Routine

        A person feeding a small dog with a measured portion of food next to a feeding station and a visible feeding schedule in a cozy home setting.

        Small dogs thrive on consistency, and getting their feeding schedule right can prevent digestive issues and behavioral problems. The key is finding the right frequency and timing that matches your pup’s age, energy level, and health needs.

        How Often to Feed Small Dogs

        Let’s be real — small dogs aren’t just tiny versions of big dogs. Their stomachs are about the size of a walnut, which means they can’t handle large meals.

        Most small dogs need to eat 2-3 times per day. Puppies under six months old should eat three to four times daily. Adult small dogs do well with twice-daily feeding.

        Here’s why frequent meals matter for small breeds:

        • Prevents hypoglycemia (low blood sugar)
        • Reduces digestive upset
        • Maintains steady energy levels
        • Prevents resource guarding behavior

        I’ve seen too many small dog owners make the mistake of filling a bowl once and leaving it out all day. This leads to overeating, food spoilage, and unpredictable bathroom schedules.

        Free feeding is a no-go for small dogs. They need structure and portion control to stay healthy.

        Sample Daily Feeding Schedules

        Creating the right schedule depends on your lifestyle and your dog’s needs. Here are three proven schedules that work:

        Two-Meal Schedule (Adult Dogs 6+ months):

        • 7:00 AM – Morning meal
        • 5:00 PM – Evening meal

        Three-Meal Schedule (Puppies or Senior Dogs):

        • 7:00 AM – Breakfast (40% of daily food)
        • 12:00 PM – Lunch (30% of daily food)
        • 5:00 PM – Dinner (30% of daily food)

        Working Owner Schedule:

        • 6:30 AM – Before work
        • 12:30 PM – Lunch break (if possible)
        • 6:30 PM – After work

        The key is spacing meals 4-6 hours apart. This prevents your pup from getting too hungry between meals.

        I always recommend feeding at least 2-3 hours before bedtime. This gives your dog time to digest and go potty before sleep.

        Adjusting for Age, Activity, and Health

        Your small dog’s feeding routine isn’t set in stone. It needs to flex with their changing needs throughout life.

        Puppies (8 weeks to 6 months):

        • Feed 3-4 times daily
        • Smaller, more frequent meals prevent blood sugar drops
        • Switch to adult schedule around 6 months

        Adult Dogs (6 months to 7 years):

        • Standard 2-meal schedule works best
        • Active dogs may need slightly larger portions
        • Couch potato pups might need portion cuts

        Senior Dogs (7+ years):

        • May benefit from 3 smaller meals
        • Easier on aging digestive systems
        • Monitor for weight changes

        High-Energy Dogs need more calories spread across their meals. Think of it like fueling a sports car — they burn through energy fast.

        Less Active Dogs need careful portion control. I’ve seen too many small dogs become overweight because owners don’t adjust for their lifestyle.

        Health Considerations:

        The bottom line? Start with a basic schedule and adjust based on what I see working for your specific pup. Their energy levels, bathroom habits, and overall happiness will tell you if you’ve got it right.

        Safe Food Choices and Sneaky Hazards

        A small dog sitting by a kitchen table with bowls of safe dog food and nearby bowls containing hazardous foods like grapes and chocolate placed out of reach.

        When I’m feeding small dogs, I know the stakes feel higher because their tiny bodies can’t handle mistakes like larger breeds can. Small breed dogs need careful food selection to avoid serious health issues, and some foods that seem harmless can actually be dangerous for their smaller systems.

        What’s Safe: Approved Proteins, Veggies, and Treats

        Let’s talk about what I actually put in my small dog’s bowl without worry. Lean proteins are my go-to foundation.

        I stick with these tried-and-true options:

        • Chicken breast (skinless, boneless)
        • Turkey (no seasoning)
        • Fish like salmon or sardines
        • Eggs (cooked, never raw)

        For veggies, I’ve learned small dogs actually love these healthy additions:

        VeggieBenefitsServing Size
        CarrotsGood for teeth, low calorie2-3 baby carrots
        Green beansFiber, vitamins5-6 pieces
        Sweet potatoVitamins A & C1 tablespoon
        BlueberriesAntioxidants3-5 berries

        I always cook vegetables until they’re soft. Raw veggies can be hard for small mouths to chew properly.

        Training treats should be tiny – like rice grain size. I break regular dog treats into quarters for my small breeds.

        Foods to Never Feed a Small Dog

        Here’s where I get serious because dogs face higher risks from toxic foods than we realize.

        Never, ever give these:

        • Chocolate (especially dark chocolate)
        • Grapes and raisins (even one grape can cause kidney failure)
        • Onions and garlic (damages red blood cells)
        • Xylitol (artificial sweetener – causes rapid blood sugar drop)

        The scary part? Small dogs can get poisoned from amounts that wouldn’t hurt a Golden Retriever. A single chocolate chip cookie could send a 5-pound Chihuahua to the emergency vet.

        Other dangerous foods I avoid:

        • Avocado (contains persin)
        • Macadamia nuts
        • Raw dough with yeast
        • Alcohol of any kind

        I keep a list on my fridge because family members sometimes forget how serious this is.

        Managing Sensitive Tummies

        Small breed dogs often have sensitive stomachs, and I’ve learned the hard way that switching foods too fast spells disaster.

        My gentle transition method:

        • Days 1-3: 75% old food, 25% new food
        • Days 4-6: 50% each
        • Days 7-10: 25% old, 75% new
        • Day 10+: 100% new food

        I watch for these warning signs of tummy trouble:

        • Loose stools or diarrhea
        • Vomiting
        • Loss of appetite
        • Excessive gas

        When feeding small dogs with sensitive stomachs, I stick to these rules. Feed smaller portions more often – 3-4 tiny meals instead of 2 big ones. Their little stomachs can’t handle large amounts at once.

        I keep meals simple when problems arise. Plain boiled chicken and white rice work wonders for upset tummies. No fancy ingredients until things settle down.

        Some small breeds need special diets forever. My friend’s Yorkie can only eat limited ingredient foods because regular kibble gives him terrible gas and loose stools.

        Avoiding Common Feeding Mistakes With Small Dogs

        Small breed dogs face unique feeding challenges that can lead to serious health problems if you don’t catch them early. The key is learning to spot warning signs and making simple adjustments before minor issues become major concerns.

        Spotting Signs of Overfeeding or Underfeeding

        Ever wonder if you’re giving your little pup just the right amount of food? I’ve seen too many small dog owners struggle with this balance, and trust me, the signs are easier to spot than you think.

        Overfeeding red flags include:

        • Difficulty feeling your dog’s ribs under their fur
        • Loss of visible waist when looking from above
        • Excessive panting during light activity
        • Reluctance to play or exercise

        Small breed dogs can gain weight quickly because their tiny bodies don’t need much extra food to tip the scales. Just two or three extra treats per day can add up fast.

        Underfeeding warning signs include:

        • Ribs, spine, or hip bones easily visible
        • Dull, brittle coat
        • Low energy levels
        • Constant food-seeking behavior

        I always tell owners to do the “rib test” weekly. Run your hands along your dog’s sides – you should feel the ribs with gentle pressure but not see them clearly.

        Recognizing changes in food intake helps prevent both overfeeding and underfeeding issues before they become serious health problems.

        Tackling Weight Gain Before It Starts

        Let’s be real – preventing weight gain is way easier than trying to get those extra pounds off later. Small dogs are particularly prone to rapid weight changes, so staying ahead of the game is crucial.

        Portion control basics:

        • Measure food with an actual measuring cup, not a random scoop
        • Divide daily portions into 2-3 smaller meals
        • Account for treats in your dog’s total daily calories

        I recommend keeping a simple feeding log for two weeks. Write down every meal, treat, and snack your dog gets. You might be surprised by how much they’re actually eating.

        Smart feeding strategies:

        • Use puzzle feeders to slow down eating
        • Set specific meal times instead of free-feeding
        • Remove uneaten food after 15-20 minutes

        Small breed dogs have faster metabolisms but also smaller stomachs. They need frequent, controlled portions rather than one big meal that might make them sick.

        Watch for sneaky calorie sources like table scraps from family members or treats from visitors. These “extras” add up fast on a tiny body.

        Mindful Treat-Giving Tips

        Here’s the kicker – treats should never make up more than 10% of your small dog’s daily calories. That means if your 10-pound dog needs 400 calories per day, only 40 calories should come from treats.

        Smart treat choices:

        • Break regular treats into smaller pieces
        • Use vegetables like carrots or green beans
        • Try frozen blueberries for a fun, low-calorie option
        • Save high-value treats for training sessions only

        I’ve learned that small dogs respond just as well to tiny treat pieces as they do to whole ones. Your pup doesn’t care about the size – they care about getting rewarded.

        Training without overfeeding:

        • Use part of your dog’s regular kibble as training treats
        • Space out treat-giving throughout the day
        • Choose soft treats you can easily break apart

        The biggest mistake I see? Using human food as treats without thinking about the calories. A small piece of cheese might be 50 calories – that’s already over the daily treat limit for many small breed dogs.

        Keep track of who’s giving treats in your household. Kids and guests often don’t realize how quickly those “just one little treat” moments add up on a 5-pound body.

        Frequently Asked Questions

        A person feeding small dogs from bowls on a kitchen floor with dog food and water nearby in a cozy home setting.

        Small dog feeding can feel overwhelming with so many conflicting opinions out there. Let me tackle the most common questions I get from fellow small dog parents about nutrition, portions, and feeding schedules.

        What’s the real deal with tailored nutrition for pint-sized pooches — do they need a special diet?

        Here’s the thing – your tiny furball absolutely needs different nutrition than their big-breed buddies. I’ve learned this the hard way with my own small dogs.
        Small breeds have faster metabolisms. They burn calories at a much higher rate than larger dogs.
        Their kibble size matters too. Those massive chunks designed for Golden Retrievers? Your Chihuahua can’t even fit them in their mouth properly.
        Small dog formulas pack more calories per cup. This helps meet their high energy needs without stuffing their tiny stomachs.
        The protein and fat content is different. Small breeds need around 18-22% protein and 8-15% fat in their dry food.
        Think of it like this – a hummingbird needs different fuel than an eagle. Your pocket-sized pup is the hummingbird of the dog world.

        Ever ponder the perfect portion size for your petite pal? How do we factor in their weight?

        I get this question constantly, and honestly, most people are shocked by how little food small dogs actually need. It’s way less than you think.
        The basic rule I follow: 1/4 to 1/2 cup of dry food per day for dogs under 10 pounds. Dogs 10-20 pounds get 1/2 to 3/4 cup daily.
        But weight isn’t everything. My active Jack Russell needs more calories than my couch-potato Pug of the same weight.
        Here’s what I consider:
        Current weight vs ideal weight
        Activity level (is your dog a zoomer or a snoozer?)
        Age (puppies and seniors have different needs)
        Health conditions
        Start with the feeding guide on your dog food bag. Then adjust based on your pup’s body condition – you should feel their ribs easily but not see them.

        Are you scratching your head over how often you should be filling Fido’s bowl? Let’s talk schedules for every stage.

        Feeding frequency changes as your small dog grows, and getting this wrong can cause some serious tummy troubles. Let me break it down by life stage.
        Puppies (8 weeks to 6 months): I feed 3-4 times daily. Their tiny stomachs can’t handle large meals, plus they’re growing like weeds.
        Young adults (6 months to 7 years): Twice daily works perfectly. Morning and evening, about 12 hours apart.
        Seniors (7+ years): I stick with twice daily but sometimes add a small midday snack if they seem hungry.
        The 2021 AAHA guidelines recommend feeding cats and small dogs appropriate portions based on their life stage needs.
        Never free-feed small dogs. They’re prone to overeating and weight gain because of their slower metabolisms as they age.

        I’ve asked countless vets this question, and their answers might surprise you. They don’t always recommend the fanciest brands.
        Royal Canin Small Breed consistently tops vet recommendation lists. The kibble size is perfect, and the nutrition profile hits all the marks.
        Hill’s Science Diet Small Paws gets high marks too. I love that they have life-stage specific formulas.
        Purina Pro Plan Small Breed offers great value without compromising quality. My vet actually feeds this to her own Yorkie.
        What vets look for:
        AAFCO feeding trial statements
        Proper kibble size for small mouths
        Balanced nutrition without fillers
        Reputable manufacturing standards
        Skip the boutique brands with weird ingredients. Stick with companies that invest in research and feeding trials.

        You want the best for your fur baby, right? So, what’s the ultimate diet to keep your small dog spry and satisfied?

        After years of trial and error with my own small dogs, I’ve found the winning formula. It’s simpler than you might think.
        High-quality commercial small breed kibble should be 80% of their diet. Choose one with real meat as the first ingredient.
        Add some variety with safe extras:
        Plain cooked chicken (10% of daily calories)
        Small pieces of carrot or green beans
        A spoonful of plain pumpkin for fiber
        I avoid grain-free diets unless there’s a medical reason. The FDA has raised concerns about these formulas and heart disease.
        Fresh water available 24/7 is non-negotiable. Small dogs dehydrate faster than large breeds.
        Keep treats under 10% of daily calories. I know those puppy eyes are hard to resist, but only 22% of dog owners get veterinary advice about treat portions.

        Baffled by all the feeding guidelines out there? How about a simple chart to track your pup’s daily dining needs by weight?

        Let me give you the feeding chart I wish someone had shared with me when I got my first small dog. I keep this taped to my pantry door.
        Daily Feeding Amounts (divide into 2 meals):
        2-5 lbs: 1/4 to 1/3 cup dry food
        6-10 lbs: 1/3 to 1/2 cup dry food
        11-15 lbs: 1/2 to 2/3 cup dry food
        16-20 lbs: 2/3 to 3/4 cup dry food
        Puppy multipliers (8 weeks to 6 months):
        Multiply adult amounts by 1.5-2x
        Divide into 3-4 meals daily
        Senior adjustments (7+ years):
        Reduce by 10-20% if less active
        Switch to senior formula
        Remember, these are starting points. Watch your dog’s body condition and adjust accordingly. When in doubt, ask your vet – they know your pup’s specific needs better than any chart.

        As an Amazon Associate, we may earn a commission from qualifying purchases if you click on the links within this article. Learn more.

        Leave a Reply