Gutenberg Block Current Year
November 3, 2024 · AI Conversations
### Step 1: Register Your Block
In your `resources/assets/scripts` folder (or wherever you keep your JavaScript files), create a new file for your block, e.g., `current-year-block.js`.
### Step 2: Add Block Code
Here’s a basic example of how to create a block that displays the current year:
import { registerBlockType } from '@wordpress/blocks';
import { useEffect, useState } from '@wordpress/element';
registerBlockType('your-namespace/current-year', {
title: 'Current Year',
category: 'widgets',
icon: 'calendar-alt',
edit: () => {
const [year, setYear] = useState(new Date().getFullYear());
useEffect(() => {
const updateYear = () => {
setYear(new Date().getFullYear());
};
// Optional: You can add an interval if you want it to update every year.
const interval = setInterval(updateYear, 1000 * 60 * 60 * 24 * 365);
return () => clearInterval(interval);
}, []);
return <div>{year}</div>;
},
save: () => {
return <div>{new Date().getFullYear()}</div>;
},
});
### Step 3: Enqueue Your Block Script
In your theme's `functions.php`, enqueue your block script using the following code:
function my_block_assets() {
wp_enqueue_script(
'current-year-block',
get_theme_file_uri('resources/assets/scripts/current-year-block.js'),
array('wp-blocks', 'wp-element'),
filemtime(get_theme_file_path('resources/assets/scripts/current-year-block.js'))
);
}
add_action('enqueue_block_editor_assets', 'my_block_assets');
### Step 4: Build Your Assets
Make sure your assets are built. If you’re using Sage 10, run the following command to build your assets:
yarn build
### Step 5: Test Your Block
1. Go to your WordPress admin dashboard.
2. Navigate to a post or page and add your "Current Year" block from the block inserter.
3. You should see the current year displayed.
### Notes
– The `edit` function uses React's `useEffect` and `useState` to keep the displayed year updated. The `setInterval` function is included as an example but isn't strictly necessary since the year doesn't change every second.
– Ensure your namespace in `registerBlockType` is unique to prevent conflicts with other blocks.
With this setup, you should have a functioning Gutenberg block that displays the current year! Let me know if you need any more assistance.
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from 'react';
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
*/
import { useBlockProps } from '@wordpress/block-editor';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* Those files can contain any CSS code that gets applied to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './editor.scss';
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {Element} Element to render.
*/
export default function Edit() {
return (
{ __(
'Copyright Date Block – hello from the editor!-2',
'copyright-date-block'
) }
);
}
### Updated `Edit` Function
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from 'react';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';
export default function Edit() {
const [year, setYear] = useState(new Date().getFullYear());
useEffect(() => {
const updateYear = () => {
setYear(new Date().getFullYear());
};
// This will update the year if needed, though it's not strictly necessary for a year display
const interval = setInterval(updateYear, 1000 * 60 * 60 * 24 * 365);
return () => clearInterval(interval);
}, []);
return (
<p { ...useBlockProps() }>
{ __( 'Copyright © ', 'copyright-date-block' ) }
{ year }
</p>
);
}
### Breakdown of Changes
1. **State Initialization**: The `useState` hook initializes the `year` state with the current year.
2. **Effect Hook**: The `useEffect` hook is used to keep the year updated if needed (you may not need this for just a year display).
3. **Rendering the Year**: The returned JSX now includes the current year alongside a copyright message. The `__(…)` function is used for translation.
### Complete Block Example
Make sure you also have the `save` function set up to keep the block content consistent on the front end. You can do this similarly:
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from 'react';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';
export function Edit() {
const [year, setYear] = useState(new Date().getFullYear());
useEffect(() => {
const updateYear = () => {
setYear(new Date().getFullYear());
};
const interval = setInterval(updateYear, 1000 * 60 * 60 * 24 * 365);
return () => clearInterval(interval);
}, []);
return (
<p { ...useBlockProps() }>
{ __( 'Copyright © ', 'copyright-date-block' ) }
{ year }
</p>
);
}
export function Save() {
const currentYear = new Date().getFullYear();
return (
<p>
{ __( 'Copyright © ', 'copyright-date-block' ) }
{ currentYear }
</p>
);
}
### Summary
With this setup, your Gutenberg block will now display the current year dynamically in the editor and save the current year to the front-end content. You can further customize the block's styles and functionality as needed. If you have any other questions or need additional features, feel free to ask!
For your block that displays the current year, you may not need extensive JavaScript since the `save` function in the block already outputs the current year. However, if you want to make sure the year updates dynamically every time the page loads, here’s how you could set up `view.js`:
### `view.js` – Dynamically Display Current Year on Front End
// Ensure this code only runs on the front end where this block is used
document.addEventListener('DOMContentLoaded', () => {
const elements = document.querySelectorAll('.wp-block-your-namespace-current-year');
elements.forEach(element => {
// Set the content to the current year
const currentYear = new Date().getFullYear();
element.textContent = `© ${currentYear}`;
});
});
### Explanation
1. **Event Listener**: `DOMContentLoaded` ensures the script runs after the DOM is fully loaded.
2. **Query the Block Elements**: It selects all instances of your block using a class selector. Replace `your-namespace-current-year` with the actual class or block name used in your block’s front-end rendering.
3. **Update Content**: It dynamically sets the year to the current year.
### Enqueue `view.js` in `functions.php`
Make sure to enqueue `view.js` only on the front end by adding it to your theme's `functions.php`:
function enqueue_current_year_block_script() {
if ( ! is_admin() ) {
wp_enqueue_script(
'current-year-block-view',
get_theme_file_uri('resources/assets/scripts/view.js'),
array(),
filemtime(get_theme_file_path('resources/assets/scripts/view.js')),
true
);
}
}
add_action('wp_enqueue_scripts', 'enqueue_current_year_block_script');
This will ensure `view.js` is only loaded on the front end, helping reduce load on the editor page. Now your custom Gutenberg block will dynamically display the current year on the front end as well!
1. **Modify `render.php`** to output a container that `view.js` can update.
2. Ensure `render.php` uses the current year as a default fallback.
### Step 1: Update `render.php`
In your `render.php` file, wrap the output with a container, and add a placeholder for the year. Here’s an example:
<?php
// Dynamic block content for Current Year
$year = date('Y');
?>
<p class="wp-block-your-namespace-current-year">© <?php echo esc_html( $year ); ?></p>
This code provides a default year value that `view.js` will target.
### Step 2: Ensure `view.js` Updates the Year
With the previous `view.js` setup, this JavaScript will update the year whenever the page loads. Since `render.php` is used as the initial structure, it will show the current year as a fallback even if `view.js` doesn’t load immediately.
### Alternative: Remove PHP Dependency for Static Year Display
If you don’t want `render.php` to control the front-end display, remove it and update the block registration in PHP so it’s not a dynamic block. To make it a static block, remove the `render_callback` in your block’s registration in PHP:
register_block_type('your-namespace/current-year', array(
'editor_script' => 'your-block-editor-script',
'editor_style' => 'your-block-editor-style',
'style' => 'your-block-frontend-style',
));
With this change, the content will be saved directly in the post content rather than relying on `render.php`, making it possible to control with JavaScript or directly within `view.js`. Let me know if you’d like more guidance with either approach!
### Step 1: Set Up `render.php` to Fetch and Display Posts
Here’s an example of how to fetch the latest post and display its title and excerpt:
<?php
// Fetch the latest post
$args = array(
'post_type' => 'post',
'posts_per_page' => 1,
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post(); ?>
<div class="wp-block-your-namespace-latest-post">
<h2><?php the_title(); ?></h2>
<div><?php the_excerpt(); ?></div>
<a href="<?php the_permalink(); ?>"><?php _e( 'Read more', 'your-text-domain' ); ?></a>
</div>
<?php endwhile;
wp_reset_postdata();
else : ?>
<p><?php _e( 'No posts found.', 'your-text-domain' ); ?></p>
<?php endif; ?>
This code snippet:
1. **Defines Query Arguments**: Sets `post_type` to `post` and `posts_per_page` to `1` to fetch only the latest post.
2. **Runs the Loop**: Checks if there are any posts matching the query, then outputs the post title, excerpt, and a "Read more" link to the full post.
3. **Resets the Post Data**: Ensures the global `$post` variable is reset after the custom query.
### Step 2: Register the Block with `render_callback`
In your block registration, specify `render.php` as the callback for generating the front-end content dynamically:
register_block_type('your-namespace/latest-post', array(
'render_callback' => 'your_namespace_render_latest_post_block',
'editor_script' => 'your-block-editor-script',
'editor_style' => 'your-block-editor-style',
'style' => 'your-block-frontend-style',
));
function your_namespace_render_latest_post_block() {
ob_start();
include plugin_dir_path( __FILE__ ) . 'render.php';
return ob_get_clean();
}
Replace `plugin_dir_path( __FILE__ ) . 'render.php'` with the correct path if `render.php` is located in a theme directory instead.
### Step 3: Customize Post Display (Optional)
To show multiple posts, adjust `posts_per_page` in `$args`:
'posts_per_page' => 3,
Now, this block will dynamically fetch and display posts based on the PHP logic in `render.php`. This approach is helpful if you need the content to be updated automatically when new posts are added. Let me know if you need any further customization!
Here’s how you can set it up:
### Step 1: Create the `edit.js` File with Fetch Logic
In your block’s `edit.js` file, use `useEffect` to fetch data when the component mounts and `useState` to store the data.
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { useEffect, useState } from 'react';
import './editor.scss';
export default function Edit() {
const blockProps = useBlockProps();
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Replace with your external API URL
const apiUrl = 'https://api.example.com/data';
// Fetch data from the API
fetch(apiUrl)
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
console.error('Error fetching data:', error);
setLoading(false);
});
}, []);
if (loading) {
return <p {...blockProps}>{__('Loading...', 'your-text-domain')}</p>;
}
if (!data) {
return <p {...blockProps}>{__('No data available', 'your-text-domain')}</p>;
}
return (
<div {...blockProps}>
<h3>{__('Fetched Data:', 'your-text-domain')}</h3>
{/* Display data as needed. This example assumes the data is an object */}
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
### Explanation
1. **State Management**: `data` holds the fetched data, and `loading` manages the loading state.
2. **Fetch Data on Mount**: The `useEffect` hook fetches data from the external API when the component mounts.
3. **Error Handling**: If the fetch request fails, it logs an error and stops the loading state.
4. **Display Logic**: While loading, it shows a "Loading…" message. Once the data is fetched, it displays the data.
### Step 2: Handle the Data (Customize as Needed)
Replace the `apiUrl` with the URL of your external API. Update the display logic within the `return` statement based on the structure of the API data.
### Example of Displaying Specific Data Fields
If the fetched data has specific fields, such as `title` and `description`, adjust the rendering:
return (
<div {...blockProps}>
<h3>{__('Fetched Data:', 'your-text-domain')}</h3>
<p>{data.title}</p>
<p>{data.description}</p>
</div>
);
### Step 3: Ensure CORS Compliance
If you encounter any CORS issues, ensure the external API allows requests from your WordPress domain by configuring CORS headers on the API side or by using a proxy.
With this setup, your Gutenberg block’s editor will display data fetched from an external API! Let me know if you need further customization.
Here are two approaches:
### Approach 1: JavaScript Fetch in `view.js` (Recommended)
This approach uses `view.js` to fetch data on the front end when the page loads.
1. **Add a `view.js` file** in your block directory.
// view.js
document.addEventListener('DOMContentLoaded', () => {
const apiUrl = 'https://api.example.com/data';
fetch(apiUrl)
.then(response => response.json())
.then(data => {
// Find the block container and populate it with the data
const elements = document.querySelectorAll('.wp-block-your-namespace-your-block-name');
elements.forEach(element => {
element.innerHTML = `
<h3>Fetched Data:</h3>
<p>${data.title}</p>
<p>${data.description}</p>
`;
});
})
.catch(error => {
console.error('Error fetching data:', error);
});
});
Replace `apiUrl` with the actual URL of the external API, and update `data.title` and `data.description` based on the structure of the API response.
2. **Enqueue `view.js` in `functions.php`** so it loads only on the front end.
function enqueue_block_view_script() {
if ( ! is_admin() ) {
wp_enqueue_script(
'your-block-view-script',
get_theme_file_uri('/path-to-your/view.js'),
array(),
filemtime(get_theme_file_path('/path-to-your/view.js')),
true
);
}
}
add_action('wp_enqueue_scripts', 'enqueue_block_view_script');
3. **Register the Block as Static**
Ensure the block is not using a `render_callback` to avoid PHP rendering conflicts. You can handle all rendering in the `view.js` script.
—
### Approach 2: Dynamic PHP Rendering (if needed)
If you need server-side rendering, register the block as a dynamic block with `render.php` and fetch the data server-side.
1. **Update `render.php` to Fetch API Data**
Use `wp_remote_get` to fetch data from the external API. Here’s a basic example:
<?php
function fetch_api_data() {
$response = wp_remote_get('https://api.example.com/data');
if (is_wp_error($response)) {
return '<p>Error fetching data.</p>';
}
$data = json_decode(wp_remote_retrieve_body($response), true);
if (! $data) {
return '<p>No data available.</p>';
}
// Customize the output
return sprintf(
'<div class="wp-block-your-namespace-your-block-name">
<h3>Fetched Data:</h3>
<p>%s</p>
<p>%s</p>
</div>',
esc_html($data['title']),
esc_html($data['description'])
);
}
function render_dynamic_block() {
return fetch_api_data();
}
2. **Register the Block with `render_callback`**
In your `init` function, set `render_callback` to use the PHP function above:
register_block_type('your-namespace/your-block-name', array(
'render_callback' => 'render_dynamic_block',
));
With either approach, you’ll have a block that dynamically fetches and displays external data on the front end. The JavaScript method (`view.js`) is more responsive, while the PHP method (`render.php`) can be useful for server-rendered content. Let me know which approach works best, or if you'd like more help!
const { showStartingYear, startingYear } = attributes;
const currentYear = new Date().getFullYear().toString();
return (
setAttributes( {
showStartingYear: ! showStartingYear,
} )
}
/>
{ showStartingYear && (
setAttributes( { startingYear: value } )
}
/>
) }
© { currentYear }
);
}
what is !!
1. **Single `!` Negates a Value**: For example, `!showStartingYear` would turn any truthy value into `false` and any falsy value into `true`.
2. **Double `!!` Reverts to Boolean**: By adding a second `!`, it turns any value into `true` or `false` based on its truthiness.
So, in the line:
checked={ !!showStartingYear }
– `!!showStartingYear` will be `true` if `showStartingYear` has a truthy value (like `true`, `1`, or a non-empty string).
– `!!showStartingYear` will be `false` if `showStartingYear` is falsy (like `false`, `0`, `null`, `undefined`, or an empty string).
This ensures `checked` receives a boolean, as required by the `ToggleControl`.
showStartingYear: !showStartingYear,
`!showStartingYear` toggles the value of `showStartingYear` to the opposite of what it currently is:
– If `showStartingYear` is `true`, `!showStartingYear` will evaluate to `false`.
– If `showStartingYear` is `false`, `!showStartingYear` will evaluate to `true`.
This line is used within the `onChange` handler for `ToggleControl` to flip the value of `showStartingYear` each time the toggle is clicked, allowing users to enable or disable the "starting year" option interactively.