diff --git a/includes/dynamic-tags/class-dynamic-tag-callbacks.php b/includes/dynamic-tags/class-dynamic-tag-callbacks.php
index da29f2662..0d759e1c5 100644
--- a/includes/dynamic-tags/class-dynamic-tag-callbacks.php
+++ b/includes/dynamic-tags/class-dynamic-tag-callbacks.php
@@ -751,4 +751,44 @@ public static function get_next_posts_page_url( $options, $block, $instance ) {
 
 		return self::output( $output, $options, $instance );
 	}
+
+	/**
+	 * Get the media.
+	 *
+	 * @param array  $options The options.
+	 * @param object $block The block.
+	 * @param object $instance The block instance.
+	 * @return string
+	 */
+	public static function get_media( $options, $block, $instance ) {
+		$id = GenerateBlocks_Dynamic_Tags::get_id( $options, 'post', $instance );
+
+		if ( ! $id ) {
+			return self::output( '', $options, $instance );
+		}
+
+		switch ( $options['key'] ?? '' ) {
+			case 'title':
+				$output = get_the_title( $id );
+				break;
+			case 'id':
+				$output = $id;
+				break;
+			case 'alt':
+				$output = get_post_meta( $id, '_wp_attachment_image_alt', true );
+				break;
+			case 'caption':
+				$output = wp_get_attachment_caption( $id );
+				break;
+			case 'description':
+				$output = get_post_field( 'post_content', $id );
+				break;
+			case 'url':
+			default:
+				$output = wp_get_attachment_url( $id );
+				break;
+		}
+
+		return self::output( $output, $options, $instance );
+	}
 }
diff --git a/includes/dynamic-tags/class-dynamic-tags.php b/includes/dynamic-tags/class-dynamic-tags.php
index 54a35f11f..971b928c3 100644
--- a/includes/dynamic-tags/class-dynamic-tags.php
+++ b/includes/dynamic-tags/class-dynamic-tags.php
@@ -316,6 +316,30 @@ public function register() {
 				'return'   => [ 'GenerateBlocks_Dynamic_Tag_Callbacks', 'get_next_posts_page_url' ],
 			]
 		);
+
+		new GenerateBlocks_Register_Dynamic_Tag(
+			[
+				'title'    => __( 'Media', 'generateblocks' ),
+				'tag'      => 'media',
+				'type'     => 'media',
+				'supports' => [],
+				'options'  => [
+					'key' => [
+						'type'    => 'select',
+						'label'   => __( 'Media Key', 'generateblocks' ),
+						'default' => 'url',
+						'options' => [
+							'url',
+							'id',
+							'caption',
+							'description',
+							'alt',
+						],
+					],
+				],
+				'return'   => [ 'GenerateBlocks_Dynamic_Tag_Callbacks', 'get_media' ],
+			]
+		);
 	}
 
 	/**
diff --git a/src/dynamic-tags/components/DynamicTagSelect.jsx b/src/dynamic-tags/components/DynamicTagSelect.jsx
index 4cb11bebf..07505ac93 100644
--- a/src/dynamic-tags/components/DynamicTagSelect.jsx
+++ b/src/dynamic-tags/components/DynamicTagSelect.jsx
@@ -262,6 +262,7 @@ export function DynamicTagSelect( { onInsert, tagName, selectedText, currentPost
 	const [ termSource, setTermSource ] = useState( '' );
 	const debouncedSetTermSource = useDebounce( setTermSource, 200 );
 	const [ userSource, setUserSource ] = useState( '' );
+	const [ mediaSource, setMediaSource ] = useState( '' );
 	const [ dynamicTagToInsert, setDynamicTagToInsert ] = useState( '' );
 	const [ metaKey, setMetaKey ] = useState( '' );
 	const debouncedSetMetaKey = useDebounce( setMetaKey, 200 );
@@ -416,6 +417,9 @@ export function DynamicTagSelect( { onInsert, tagName, selectedText, currentPost
 			} else if ( 'user' === type ) {
 				setDynamicSource( 'user' );
 				setUserSource( id );
+			} else if ( 'media' === type ) {
+				setDynamicSource( 'media' );
+				setMediaSource( id );
 			} else {
 				setDynamicSource( 'post' );
 				setPostIdSource( id );
@@ -513,6 +517,8 @@ export function DynamicTagSelect( { onInsert, tagName, selectedText, currentPost
 			setDynamicSource( 'term' );
 		} else if ( userSource && 'user' === dynamicTagType && 'user' !== dynamicSource ) {
 			setDynamicSource( 'user' );
+		} else if ( mediaSource && 'media' === dynamicTagType && 'media' !== dynamicSource ) {
+			setDynamicSource( 'media' );
 		} else if ( ! dynamicSource ) {
 			setDynamicSource( 'current' );
 		}
@@ -525,8 +531,10 @@ export function DynamicTagSelect( { onInsert, tagName, selectedText, currentPost
 			options.push( `id:${ postIdSource }` );
 		} else if ( termSource && 'term' === dynamicSource ) {
 			options.push( `id:${ termSource }` );
-		} else if ( 0 < userSource && 'user' === dynamicSource ) {
+		} else if ( userSource && 'user' === dynamicSource ) {
 			options.push( `id:${ userSource }` );
+		} else if ( mediaSource && 'media' === dynamicSource ) {
+			options.push( `id:${ mediaSource }` );
 		}
 
 		if ( tagSupportsMeta && metaKey ) {
@@ -604,6 +612,7 @@ export function DynamicTagSelect( { onInsert, tagName, selectedText, currentPost
 		tagSupportsTaxonomy,
 		tagSupportsLink,
 		dateFormat,
+		mediaSource,
 	] );
 
 	const interactiveTagNames = [ 'a', 'button' ];
@@ -722,6 +731,24 @@ export function DynamicTagSelect( { onInsert, tagName, selectedText, currentPost
 						</>
 					) }
 
+					{ 'media' === dynamicSource && (
+						<>
+							<SelectPost
+								label={ __( 'Select source media', 'generateblocks' ) }
+								value={ mediaSource }
+								onChange={ ( selected ) => setMediaSource( selected?.value ?? '' ) }
+								onClear={ () => setMediaSource( '' ) }
+								onAdd={ ( { inputValue } ) => setMediaSource( inputValue ) }
+								onEnter={ ( inputValue ) => {
+									setMediaSource( inputValue );
+								} }
+								currentPostId={ currentPostId }
+								includeCurrent={ false }
+								postStatus={ [ 'inherit' ] }
+							/>
+						</>
+					) }
+
 					{ 'user' === dynamicSource && (
 						<>
 							<SelectUser