<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>PavelZanek.com - Blog</title>
        <link>https://www.pavelzanek.com/en/blog</link>
        <description>My articles, insights, and updates from practice</description>
        <language>en</language>
        <lastBuildDate>Wed, 20 May 2026 07:01:58 +0200</lastBuildDate>
        <atom:link href="https://www.pavelzanek.com/en/feed.xml" rel="self" type="application/rss+xml"/>

                    <item>
                <title><![CDATA[How to generate files in Laravel using Artisan Console – command &quot;make:&quot;]]></title>
                <link>https://www.pavelzanek.com/en/blog/artisan-console-command-make</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/artisan-console-command-make</guid>
                <pubDate>Fri, 01 Sep 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[This guide will walk you through using the make command in the Laravel Artisan Console. Learn how to quickly generate classes, edit templates, and efficiently resolve common errors.]]></description>
                
                                    <content:encoded><![CDATA[What is Artisan Console in Laravel
Artisan Console is a powerful command-line tool that is part of Laravel, a popular PHP framework. It allows developers to easily and quickly perform various tasks related to application development, from code generation to database management. Artisan is an essential tool for efficient and productive development in Laravel.

Overview of the 'Make' Command and Its Significance
The 'make' command in the Artisan Console is designed to generate various types of files that are commonly used in the development of Laravel applications. With this command, you can easily and quickly create controllers, models, migrations, tests, and many other components. The 'make' command significantly increases developer productivity by automating routine tasks associated with creating new files and classes.

Why the 'Make' Command is Important

It allows developers to quickly and consistently generate code, increasing efficiency and reducing the possibility of errors.
It boosts productivity by automating repetitive tasks, allowing developers to focus on the logic and functionality of the application.
It is flexible and allows developers to customize the generated files according to their needs.


Basics of the 'Make' Command

What is the 'Make' Command
The 'make' command is part of the Artisan Console in Laravel. It allows developers to generate various types of files that are necessary for the development of a Laravel application. This command is designed to automate and simplify the process of creating new components of the application.

How to Use the 'Make' Command

To use the 'make' command, open the terminal and navigate to the root directory of your Laravel application.
Enter php artisan make: followed by the name of the component you want to create.


Example of Use
Creating a new controller:
php artisan make:controller UserController

Various Options and Parameters
The 'make' command has various options and parameters that allow developers to specify what type of file they want to create and what properties it will have.

Table of Options and Parameters

ParameterDescription
-mCreates a migration file for the model
--resourceCreates a resource controller
--apiCreates a controller for API
--factoryCreates a factory for the model
--seedCreates a seeder for the model


Example of Use with Parameters
Generating a model along with the corresponding database migration:
php artisan make:model Post -m

Where to Find the Generated Files
After running the 'make' command, the newly created files are placed in the corresponding directories of the Laravel application. For example: Controllers are located in the app/Http/Controllers directory.

Generating Various Types of Files

NameShort Description
make:castGenerates a new custom Eloquent cast class
make:channelCreates a new channel class for broadcasting events
make:componentGenerates a new view component class
make:commandCreates a new Artisan command class
make:controllerGenerates a new controller class
make:eventCreates a new event class
make:exceptionGenerates a new custom exception class
make:factoryCreates a new model factory
make:jobGenerates a new job class for the queue
make:listenerCreates a new event listener class
make:mailGenerates a new email class
make:middlewareCreates a new middleware class
make:modelGenerates a new Eloquent model class
make:notificationCreates a new notification class
make:observerGenerates a new observer class
make:policyCreates a new policy class
make:providerGenerates a new service provider class
make:requestCreates a new form request class
make:resourceGenerates a new resource class
make:ruleCreates a new validation rule class
make:scopeGenerates a new Eloquent query scope class
make:seederCreates a new seeder class
make:testGenerates a new test class
make:livewireCreates a new Livewire component
make:migrationCreates a new migration file


This table provides a quick reference guide for the various types of files that can be generated using the make command in Laravel's Artisan Console. Each row in the table represents a different make command, along with a short description of what that command is used for.

Working with Templates (Stubs)

What Are Templates (Stubs)
Templates, known as stubs, are file templates that Artisan uses when generating new classes and files. Essentially, they are predefined code templates that Laravel uses as a basis for generating new files.

How to Use Templates
When you use the make command, Artisan automatically uses the corresponding template to generate a new file. However, you can also modify these templates according to your needs.

Example
If you want to modify the template that Laravel uses to generate new controllers, you can find the corresponding template in the directory: vendor/laravel/framework/src/Illuminate/Routing/Console/stubs

Customizing Templates
Laravel allows for the publishing and customization of these templates. After publishing the templates, you can edit their content according to your needs.

How to Publish Templates

Run the following Artisan command:php artisan stub:publish
This command will copy all the templates to the stubs/ directory in your application's root directory.
Now you can edit these files according to your needs.


Why Customize Templates
Customizing templates allows you to define your own structure and content for the generated files. This is useful if you want all your generated files to have a consistent style and structure that aligns with your coding standards.

Advanced Techniques and Tips

Creating Custom 'Make' Commands
Laravel allows you to create custom Artisan commands, including custom 'make' commands. This is useful if you need to generate specific types of files that are not included by default in Laravel.

How to Create a Custom 'Make' Command

Create a New Command:php artisan make:command CustomMakeCommand
Edit the Command File:Open the newly created command file (e.g., app/Console/Commands/CustomMakeCommand.php) and set up the file generation logic.
Register the Command:Add the new command to the $commands array in the Kernel class in app/Console/Kernel.php.
Now You Can Use Your New Make Command Just Like Any Other Artisan Command:Use the Command: php artisan make:custom


Automating the File Generation Process
You can create scripts or Artisan commands that automate the file generation process to reduce the need for manual command input.

Example of Automation
Creating an Artisan command that automatically generates a model, controller, migration, and seeder all at once:
Artisan::call('make:model', ['name' => 'Post', '--migration' => true, '--controller' => true]);
Artisan::call('make:seeder', ['name' => 'PostsTableSeeder']);

Optimizing Templates for Teamwork
If you are working in a team, it is important to ensure that all generated files will have a consistent and expected structure. Customized templates can be saved in a version control system (e.g., Git) so that the entire team can use them.

Tips for Teamwork

Share Customized Templates: Save them in a repository so that the entire team has access.
Document Changes: When you modify a template, document what and why you changed it to make it clear for other team members.


Common Errors and How to Solve Them

Error: Class Already Exists
This error occurs when you try to create a class that already exists in the application.

Solution

Check the Directory: Make sure that the class actually already exists by browsing the relevant directory.
Rename the Class: If you need to create a new class with a different purpose, consider renaming the class to avoid a name conflict.


Error: Invalid Class Name
This error occurs if you enter an invalid class name when using the make command.

Solution

Check the Syntax: Make sure that the class name is in the correct format. It should start with an uppercase letter and must not contain invalid characters.
Use the Correct Command: Ensure that you are using the correct Artisan command to generate the desired type of file.


Error: Template Not Found
This error occurs if Laravel cannot find the required template (stub) for generating a file.

Solution

Check the Template Directory: Make sure that all templates are in the correct place in the stubs/ directory in your application's root directory.
Republish the Templates: If some templates are missing, try republishing them using the command:php artisan stub:publish


Error: Syntax Error in Generated File
This error occurs if there is a PHP syntax error in the generated file.

Solution

Check the Templates: The error may be in the template that Laravel used to create the file. Check the template and correct the error.
Check the Generated File: Open the generated file and locate and correct the PHP syntax error.


Conclusion

The make command in Laravel's Artisan Console is a powerful tool that significantly increases a developer's productivity by automating the process of creating new classes and files.
It allows for the generation of various types of files, from controllers and models to tests and migrations.
Templates (stubs) are a key part of this process and can be customized according to the developer's needs.
Common errors when using the make command are easily solvable and usually relate to class names, template locations, or PHP syntax.


The Importance of Effectively Using the 'Make' Command
Effectively using the make command can significantly improve a developer's workflow, enabling faster development and reducing the risk of errors by providing consistent and reliable ways of generating code. It is a tool that should be part of every Laravel developer's arsenal.

Recommendations for Next Steps

Explore More Artisan Commands: Laravel Artisan offers many other commands that can facilitate development. Try, for example, php artisan list to display all available commands.
Study Laravel's Documentation: Laravel's documentation is a rich source of information. Dedicate time to browsing through it and learn about the additional features that the framework offers.
]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/1c/1c5eb3d6-5042-4d77-8c7b-bf256ae25984/conversions/artisan-console-command-make-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Generative AI: Rapid Rise and Impact on the Tech World]]></title>
                <link>https://www.pavelzanek.com/en/blog/generative-ai-rapid-rise-impact-tech-world</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/generative-ai-rapid-rise-impact-tech-world</guid>
                <pubDate>Tue, 15 Aug 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Find out how generative AI is changing the tech world – from chat to image creation. Read about its impact on users, the market and what the future holds.]]></description>
                
                                    <content:encoded><![CDATA[Growth of Generative AI in Numbers
Generative AI reached over 100 million users just two months after the launch of ChatGPT. In contrast, smartphones took more than two years to reach 100 million users after the iPhone was introduced in 2007. Tablets reached 75 million users approximately two years after the iPad was launched in 2010. Thus, the adoption of generative AI has significantly outpaced both of these categories.

Demographic Trends in Generative AI
According to Emarketer, the adoption of generative AI among 18-34-year-olds is nearly double compared to older demographic groups. Younger generations are more digitally adept and are early adopters of new technologies, such as generative AI.

Applications of Generative AI
While generative AI has been around for some time, it has recently seen a massive surge in popularity. Users are enthusiastically experimenting with tools like ChatGPT for poetry creation, Midjourney for art generation, and AI chatbots from companies like Google and Microsoft integrated into search.

Opportunities and Risks for Marketers
For SEO specialists and digital marketers, generative AI presents both opportunities and risks. AI-driven search, such as Google's Search Generative Experience (SGE), aims to improve search quality. However, there are concerns that SGE might promote more low-quality content.

Looking to the Future
As generative AI continues to evolve, marketers should closely monitor developments. With careful testing and evaluation, there is potential to harness these tools while minimizing possible downsides.]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/fa/fa050d05-435b-4575-9d5f-72af1957a27e/conversions/insiderintelligence-generative-ai-rapid-rise-impact-tech-world-full.png" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Amazon and a revolutionary tool for generating product descriptions using AI]]></title>
                <link>https://www.pavelzanek.com/en/blog/amazon-ai-generating-product-descriptions</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/amazon-ai-generating-product-descriptions</guid>
                <pubDate>Sun, 13 Aug 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Amazon is testing a new AI tool for generating product descriptions, which could fundamentally change e-commerce. This tool has the potential to streamline the description creation process.]]></description>
                
                                    <content:encoded><![CDATA[Amazon and a revolutionary tool for generating product descriptions using AI
Amazon is testing a new AI tool for generating product descriptions, which could fundamentally change e-commerce. This tool, currently in the testing phase, has the potential to streamline the description creation process and increase sales.
Amazon, the global e-commerce giant, is currently testing a new tool based on generative artificial intelligence (AI) that has the potential to fundamentally change the way sellers create product descriptions.
Artificial Intelligence and Product Description Creation
According to media reports, especially from the news site The Information, Amazon's new AI tool allows sellers to generate titles, descriptions, and key points for products. Simply enter keywords characterizing the product, and the AI will suggest a potential title and details for the listing.
This tool is currently in the testing phase and is available to a limited number of sellers. Amazon confirmed that they are working on a solution to help sellers better engage customers.
Rules for AI-Generated Content
Although this tool can significantly reduce copywriting demands, Amazon emphasizes that replacing human review and editing is not on the agenda. The company has strict rules for product descriptions, which include adhering to relevant styles, avoiding the use of HTML, JavaScript, or offensive content.
E-commerce Platforms and AI Tools
Amazon is not the first to implement generative AI tools for sellers. BigCommerce, Shopify, and Wix have already introduced their own AI solutions that assist sellers in various areas, from chatbots to content generation.
The Greater Impact of Generative AI in E-commerce
The introduction of this tool could give Amazon sellers a significant advantage by reducing the time spent writing product descriptions. More accurate product descriptions could lead to higher sales and fewer returned goods. However, it's important to be aware of potential challenges and limitations associated with implementing AI solutions.
Source: Search Engine Journal]]></content:encoded>
                
                                    <category><![CDATA[Artificial Intelligence]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/10/1048a46a-e989-4d91-8be3-d5ff499d5cc3/conversions/amazon-ai-generating-product-descriptions-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[How to create RSS feed in Laravel framework]]></title>
                <link>https://www.pavelzanek.com/en/blog/rss-feed-laravel</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/rss-feed-laravel</guid>
                <pubDate>Thu, 10 Aug 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Find out how to easily and quickly create an RSS feed in the Laravel framework. This guide will show you the entire process from creating routes and a controller to the XML file output.]]></description>
                
                                    <content:encoded><![CDATA[RSS feed, also known as "Really Simple Syndication," is a tool that allows users to easily follow updates from websites or applications. Instead of having to regularly visit specific websites, users can simply subscribe to an RSS feed and receive news directly in their RSS reader.

Real-time Updates: As soon as new content is published, it is immediately distributed to all subscribers of the RSS feed.
Personalization: Users can choose which websites or topics they want to follow, allowing them access to content that is most relevant to them.
Efficiency: RSS feeds save users time by providing a centralized way to track updates from various sources.

Importance of Manually Creating an RSS Feed
Although there are many tools and packages that facilitate the creation of an RSS feed, it is essential to understand the basic principles and know how to create an RSS feed manually. This understanding enables you:

Greater Control: You have full control over the content included in your feed and how it is presented.
Flexibility: You can tailor your RSS feed to the specific needs of your project.
Better Understanding: When you create an RSS feed manually, you gain a deeper understanding of how the technology works, which can assist you in troubleshooting or further development.

In the following sections, we will look at how to create an RSS feed in the Laravel framework without using any external packages.
What is an RSS Feed and Why is it Important
Definition of an RSS Feed
RSS, short for "Really Simple Syndication," is a standardized format for distributing and publishing content on the internet. It allows websites and applications to share updates, news, and other content in a universal format that RSS readers can easily interpret and display.

Format: An RSS feed is typically in XML format, allowing for easy integration with various platforms and applications.
Structure: It contains basic information about the channel (e.g., name, description, website link) and items (individual articles or updates) with titles, descriptions, links, and other metadata.

Advantages of Using an RSS Feed
RSS feeds offer several benefits to websites, applications, and their users:

Centralized Content Tracking: Users can follow updates from many different sources in one place using an RSS reader.
Automation: Websites and applications can automatically generate and update their RSS feeds, ensuring users always receive the latest content.
Increased Traffic: RSS feeds can attract more visitors to your website, as users can easily follow your updates and click on links that lead them back to your pages.
Reduced Server Load: Instead of users constantly loading the entire web page, they can simply download a small RSS feed, reducing the load on the server.

RSS feeds have become a key tool for sharing content on the internet. They offer an efficient way to distribute and consume content, providing numerous benefits for both publishers and end-users. Whether you are a developer, marketer, or ordinary user, understanding RSS and its advantages can bring you many benefits.
Basics of the Laravel Framework
What is Laravel?
Laravel is a modern PHP framework designed to make it easier for developers to create robust and scalable web applications. With its modularity and rich set of tools, it quickly became one of the most popular PHP frameworks on the market.

Architecture: Laravel uses the model-view-controller (MVC) architecture, facilitating code organization and separation of application logic from presentation.
Elegance: Laravel is known for its "elegant" code, meaning it is easily readable, well-organized, and intuitive.

Key Features of Laravel
Laravel offers a range of tools and features that facilitate web application development:

Eloquent ORM: An intuitive way to work with databases through object-relational mapping.
Blade Templating Engine: A flexible and powerful tool for creating dynamic web pages.
Migrations and Seeders: Tools for easy creation and populating of databases.
Middleware: Filters that can perform various tasks before or after processing an HTTP request.
Artisan: A powerful command line for various tasks such as code generation or database management.


Why Use Laravel for Creating an RSS Feed?
Although there are many frameworks that can be used to create an RSS feed, Laravel offers several advantages:

Easy Integration: Laravel has built-in tools and libraries that make integrating an RSS feed into your application straightforward.
Security: Laravel includes several security features that protect your RSS feed from various threats.
Performance: With optimized code and efficient caching, Laravel can provide fast and reliable RSS feeds.

Laravel is a powerful and flexible framework that offers everything developers need to create quality web applications. Whether you're a beginner or an experienced developer, Laravel can provide you with the tools and resources needed to create efficient and secure RSS feeds.
Steps to Create an RSS Feed in the Laravel Framework
1. Setting Up the Database and Models
Before starting to create the RSS feed, it is essential to have the database and models set up correctly, representing the content you want to include in your feed.

Database Configuration: Ensure that you have the correct connection details set up in the .env file.
Creating a Model: Use the Artisan command php artisan make:model ModelName to create a new model.

Migration (database/migrations/{timestamp}_create_posts_table.php):
&lt;?php
  
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
  
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table-&gt;id();
            $table-&gt;string('title');
            $table-&gt;string('slug');
            $table-&gt;text('body');
            $table-&gt;timestamps();
        });
    }
  
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
};
Model (app/Models/Post.php):
&lt;?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class Post extends Model
{
    use HasFactory;
  
    protected $fillable = [
        'title', 'slug', 'body'
    ];
}
2. Creating a Controller for Generating the RSS Feed
The controller will be responsible for generating the XML structure of the RSS feed.

Creating the Controller: Use the Artisan command 'php artisan make:controller RssFeedController' to create a new controller.
Generating XML: In the controller, create a method that will generate the XML structure of the RSS feed based on data from the database.

Controller (app/Http/Controllers/RSSFeedController.php):
&lt;?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use App\Models\Post;
  
class RSSFeedController extends Controller
{
    public function index()
    {
        $posts = Post::latest()-&gt;get();
  
        return response()-&gt;view('rss', [
            'posts' =&gt; $posts
        ])-&gt;header('Content-Type', 'text/xml');
    }
}
Template (resources/views/rss.blade.php):
&lt;?=
'&lt;?xml version="1.0" encoding="UTF-8"?&gt;'.PHP_EOL
?&gt;
&lt;rss version="2.0"&gt;
    &lt;channel&gt;
        &lt;title&gt;&lt;![CDATA[ PavelZanek.com.com ]]&gt;&lt;/title&gt;
        &lt;link&gt;&lt;![CDATA[ https://your-website.com/feed ]]&gt;&lt;/link&gt;
        &lt;description&gt;&lt;![CDATA[ Your website description ]]&gt;&lt;/description&gt;
        &lt;language&gt;en&lt;/language&gt;
        &lt;pubDate&gt;{{ now()-&gt;toRssString() }}&lt;/pubDate&gt;
  
        @foreach($posts as $post)
            &lt;item&gt;
                &lt;title&gt;{{ $post-&gt;title }}&lt;/title&gt;
                &lt;link&gt;{{ $post-&gt;slug }}&lt;/link&gt;
                &lt;description&gt;&lt;![CDATA[{!! $post-&gt;body !!}]]&gt;&lt;/description&gt;
                &lt;category&gt;{{ $post-&gt;category }}&lt;/category&gt;
                &lt;author&gt;Pavel Zaněk&lt;/author&gt;
                &lt;guid&gt;{{ $post-&gt;id }}&lt;/guid&gt;
                &lt;pubDate&gt;{{ $post-&gt;created_at-&gt;toRssString() }}&lt;/pubDate&gt;
            &lt;/item&gt;
        @endforeach
    &lt;/channel&gt;
&lt;/rss&gt;
3. Setting Up the Route for the RSS Feed
To make your RSS feed accessible to users and RSS readers, you need to set up a route that will point to your controller.

Adding the Route: In the web.php file, add a new route that will point to the method in the RssFeedController that generates the RSS feed.

Route (routes/web.php):
&lt;?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\RSSFeedController;

Route::get('feed', [RSSFeedController::class, 'index'])-&gt;name('rss-feed');
4. Testing and Verifying the Functionality of the RSS Feed
After completing the above steps, it's important to verify that your RSS feed is working correctly.

Verification in the Browser: Open your RSS feed in a web browser and ensure you see the correct XML structure.
RSS Feed Validation: Use online tools, such as the W3C Feed Validation Service, to verify the correctness of your RSS feed.

Creating an RSS feed in the Laravel framework may require several steps, but thanks to the flexibility and tools Laravel offers, this process is easy and straightforward. Now that you have your RSS feed set up and functional, you can start sharing your content with a wider audience and benefit from the advantages RSS feeds offer.
Tips and Tricks for Optimizing the RSS Feed
1. How to Secure Your RSS Feed
Securing your RSS feed is crucial for protecting your data and users. The following tips will help ensure your RSS feed is safe:

Use HTTPS: Always use HTTPS for your RSS feeds to ensure data is transmitted encrypted.
Access Verification: If you want to restrict access to your RSS feed, you can implement user authentication.
Input Validation: Verify all inputs that might affect the content of your RSS feed to prevent SQL injection and other attacks.

2. How to Optimize the Performance of the RSS Feed
Optimizing the performance of your RSS feed ensures fast loading and a better user experience. Here are some tips to achieve this:

Caching: Using caching for your RSS feeds can significantly increase loading speed. Laravel offers various caching options you can utilize.
Minimize Size: Limit the size of your RSS feed by including only essential information and minimizing the use of whitespace and comments.
Proper XML Structure: Ensure your XML is correctly structured and valid. Invalid XML can cause issues when reading your RSS feed.

3. Personalization and Extension of Your RSS Feed
You can add more value to your RSS feed by customizing and extending it according to your audience's needs:

Content Customization: You can offer different versions of your RSS feed for various languages or topics.
Extended Metadata: By using extended metadata, such as images, authors, or categories, you can provide richer information about your content.

Optimizing and securing your RSS feed are critical aspects that shouldn't be overlooked. By using these tips and tricks, you can ensure your RSS feed is not only fast and secure but also tailored and extended to meet your audience's needs. Laravel offers many tools and features that can help you achieve these goals, so don't hesitate to use them in your project.
Conclusion
Throughout this guide, we've covered the key aspects of creating an RSS feed in the Laravel framework:

Definition and Importance of RSS Feed: We've conceptualized RSS as a tool for distributing and publishing content, bringing numerous benefits to websites and their users.
Basics of the Laravel Framework: We introduced Laravel as a powerful and flexible framework ideal for creating RSS feeds.
RSS Feed Creation Process: We walked step by step through the process of creating an RSS feed, from setting up the database and models to testing and verifying functionality.
Optimization and Security: We offered tips and tricks on how to secure and optimize your RSS feed for better performance and user experience.

Now that you have all the information and tools needed to create your own RSS feed in the Laravel framework, it's time to get to work! Create your RSS feed, experiment with various features, and optimize it according to your audience's needs. And don't forget to share your experiences and successes with the community!
Thank you for reading this guide. I hope it provided you with valuable information and insights to help you create a successful RSS feed in the Laravel framework. If you have further questions or need additional assistance, feel free to reach out to the Laravel community or to me. Best of luck in your development!]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/9f/9fe6f451-100d-4000-9f2d-336f55c023de/conversions/laravel-rss-feed-example-full.png" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Google HowTo and FAQ Rich Results – How to do it?]]></title>
                <link>https://www.pavelzanek.com/en/blog/google-howto-faq-rich-results</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/google-howto-faq-rich-results</guid>
                <pubDate>Wed, 09 Aug 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Find out how to implement HowTo and FAQ Rich Results for Google to improve your visibility in search results and attract more visitors to your website.]]></description>
                
                                    <content:encoded><![CDATA[What are Google's Rich Results?
Google's Rich Results, also known as Rich Results, are a special way of displaying website content in search results. They can include carousels with larger images, such as recipes, or they can be displayed with stars for ratings.
Why is Google changing the visibility of HowTo and FAQ?
The main reason Google is making these changes is to provide users with a "cleaner and more consistent search experience." Google is now limiting the display of FAQ rich results only to government and health websites with high authority. So, the FAQ will only be displayed on authoritative websites (government websites and healthcare websites). And HowTo will only be visible on desktop.

What are the implications for publishers?
Many publishers have invested time and resources in adding FAQ content and the relevant structured data. This news may be seen as a disappointment for those who hoped for better visibility through these rich results.
Should you remove FAQ &amp; HowTo structured data?
Even though Google ignores this structured data for the purposes of rich results, other search engines might use it. If it's difficult for you to remove it, it's not necessary. However, if you use a plugin or another feature, removal should be easy.
What's next for webmasters?
It's important to monitor how these changes manifest in your search results and adjust your SEO strategy accordingly. While some rich results may be less visible, there are still other opportunities to increase the visibility of your content in search.
Source: Search Engine Journal, Google Search Central]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/a4/a4499a58-1752-4ca8-9037-69c2d1d182b0/conversions/google-howto-faq-rich-results-featured-image-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Laravel Livewire CRUD]]></title>
                <link>https://www.pavelzanek.com/en/blog/laravel-livewire-crud</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/laravel-livewire-crud</guid>
                <pubDate>Thu, 29 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Learn how to build a fully functional CRUD application using Laravel and Livewire. This tutorial covers everything from installation to deployment.]]></description>
                
                                    <content:encoded><![CDATA[We will step into the world of Laravel and Livewire, where we will learn how to create a Livewire component for CRUD operations. Laravel is one of the most popular PHP frameworks, and Livewire is its powerful supplement that allows you to create modern, dynamic interfaces directly in Laravel. CRUD operations - Create, Read, Update, and Delete - are the basic building blocks of any application. In this article, we will focus on how to create a Livewire component in Laravel that allows these basic operations to be performed. In addition, we will learn how to test these components to make our application robust and reliable. Prepare for a journey full of code, innovation, and best practices in web application development.
What is Livewire and Laravel
Before we get into the tutorial itself, where we will show you step by step how to create logic in the Livewire component, it is good to familiarize yourself with both frameworks. Perhaps there are newcomers among you who are hearing about Laravel or Livewire for the first time.
Laravel
Laravel is an open-source PHP framework, highly appreciated for its elegant syntax and the ability to facilitate web application development by providing tools for common tasks such as routing, authentication, sessions, and caching. Laravel is built on Symfony components and its source code is hosted on GitHub.
Livewire
Livewire, on the other hand, is a full-fledged framework for Laravel that allows creating dynamic interfaces simply and without the need to write JavaScript. Livewire utilizes the concept of components, similar to React or Vue, but written in pure PHP. This means that you can create complex, reactive applications with a single language.
Together, Laravel and Livewire form a powerful combination for web application development. Laravel provides the basic infrastructure and Livewire adds a dynamic layer, enabling developers to create interactive user interfaces with minimal code and complexity.
Introduction to our demonstration
To better understand the demonstration, first go through the previously created article on working with CRUD operations in Laravel itself, where, in addition to basic information (e.g., what is CRUD), you will learn parts of the code that are prerequisites for further steps in this tutorial (migration, model, actions, etc.). This tutorial then assumes that you already have the Laravel framework installed along with Laravel Livewire.
For testing the Livewire component, we will also use the Pest package, which we also utilized in the previous tutorial.
Creating a Livewire Component
Creating a Livewire component in Laravel is a process that is simple and straightforward. We start by opening the terminal and navigating to the root directory of our Laravel project. Here, we can create a new Livewire component using the following command:
php artisan make:livewire ComponentName
Replace "ComponentName" with the name of your component. This command creates two new files: a component class and an associated Blade view/template. The component class is located in "app/Http/Livewire" and the Blade view is in "resources/views/livewire".
The component class is where you define all the logic of the component. It can contain public properties that are automatically synchronized between the backend and frontend, and methods that can respond to user events.
The Blade view is where you define the HTML interface of the component. You can use any valid Blade syntax/directive here, and you can also access the public properties and methods of the component class.
Creating a Livewire component is therefore a matter of creating these two files and defining the necessary logic and interface. Once you have these files prepared, you can start using your Livewire component in any Laravel view using the Livewire directive:
@livewire('component-name')
Again, replace "component-name" with the name of your component. This directive inserts your Livewire component into your template.
Demonstration of Laravel Livewire Component for CRUD Operations
However, our goal is to create a component that will process data from the "example_items" table, which we created according to the previous tutorial. So let's take a look at what the code might look like in the component class and in the Blade template.
Livewire Component Class ("app/Http/Livewire/Examples")
&lt;?php

namespace App\Http\Livewire\Examples;

use App\Actions\Examples\ExampleItems\CreateExampleItemAction;
use App\Actions\Examples\ExampleItems\RemoveExampleItemAction;
use App\Actions\Examples\ExampleItems\UpdateExampleItemAction;
use App\Enums\Examples\ExampleItemType;
use App\Models\Examples\ExampleItem;
use Illuminate\Validation\Rules\Enum;
use Livewire\Component;
use Livewire\WithPagination;

class ExampleItemManager extends Component
{
    use WithPagination;

    public $q;
    public $sortBy = 'created_at';
    public $sortAsc = false;

    public $item;
    public $exampleItemTypes;

    public $confirmingItemDeletion = false;
    public $confirmingItemAdd = false;

    protected $queryString = [
        'q' =&gt; ['except' =&gt; ''],
        'sortBy' =&gt; ['except' =&gt; 'created_at'],
        'sortAsc' =&gt; ['except' =&gt; false],
    ];

    public function mount()
    {
        $this-&gt;exampleItemTypes = ExampleItemType::all();
    }

    public function render()
    {
        $items = ExampleItem::when($this-&gt;q, function($query) {
                return $query-&gt;where(function( $query) {
                    $query-&gt;where('title', 'like', '%' . $this-&gt;q . '%');
                });
            })
            -&gt;orderBy($this-&gt;sortBy, $this-&gt;sortAsc ? 'ASC' : 'DESC')
            -&gt;paginate(20);

        return view('livewire.examples.example-item-manager', [
            'items' =&gt; $items,
        ]);
    }

    public function updatingQ() 
    {
        $this-&gt;resetPage();
    }

    public function sortBy($field) 
    {
        if( $field == $this-&gt;sortBy) {
            $this-&gt;sortAsc = !$this-&gt;sortAsc;
        }
        $this-&gt;sortBy = $field;
    }

    public function confirmItemAdd() 
    {
        $this-&gt;reset(['item']);
        $this-&gt;confirmingItemAdd = true;
    }

    public function confirmItemEdit(ExampleItem $exampleItem) 
    {
        $this-&gt;resetErrorBag();
        $this-&gt;item = $exampleItem-&gt;toArray();
        $this-&gt;confirmingItemAdd = true;
    }

    public function saveItem() 
    {
        $validatedData = $this-&gt;validate([
            'item.title' =&gt; 'required|string|max:255',
            'item.body' =&gt; 'nullable|string',
            'item.is_active' =&gt; 'nullable|boolean',
            'item.type' =&gt; [
                'required',
                'string',
                'max:8',
                new Enum(ExampleItemType::class),
            ],
        ]);

        if(isset($this-&gt;item['id'])) {
            (new UpdateExampleItemAction())-&gt;execute(
                ExampleItem::find($this-&gt;item['id']),
                $validatedData['item']
            );

            $this-&gt;dispatchBrowserEvent('alert',[
                'type'=&gt;'success',
                'message'=&gt; __('Example Item was successfully updated.')
            ]);
        } else {
            (new CreateExampleItemAction())-&gt;execute($validatedData['item']);

            $this-&gt;dispatchBrowserEvent('alert',[
                'type'=&gt;'success',
                'message'=&gt; __('Example Item was successfully created.')
            ]);
        }

        $this-&gt;reset(['item']);
        $this-&gt;confirmingItemAdd = false;
    }

    public function confirmItemDeletion($id) 
    {
        $this-&gt;confirmingItemDeletion = $id;
    }

    public function deleteItem(ExampleItem $exampleItem) 
    {
        (new RemoveExampleItemAction())-&gt;execute($exampleItem);

        $this-&gt;confirmingItemDeletion = false;

        $this-&gt;dispatchBrowserEvent('alert',[
            'type'=&gt;'success',
            'message'=&gt; __('Example Item was successfully removed.')
        ]);
    }
}
Blade view for Livewire Component ("resources/views/views/livewire/examples")
&lt;div class="p-4 border-b border-gray-200"&gt;

    &lt;div class="mt-2 text-2xl flex justify-between"&gt;
        &lt;div class="text-gray-900 dark:text-gray-100"&gt;{{ __('Example Item Manager') }}&lt;/div&gt; 
        &lt;div class="mr-2"&gt;
            &lt;x-button wire:click="confirmItemAdd" class="bg-blue-500 hover:bg-blue-700"&gt;
                {{ __('Add New Item') }}
            &lt;/x-button&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="mt-6"&gt;
        &lt;div class="flex justify-between"&gt;
            &lt;div class=""&gt;
                &lt;input wire:model.debounce.500ms="q" type="search" placeholder="{{ __('Search') }}" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5  dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" /&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="flex flex-col"&gt;
            &lt;div class="overflow-x-auto sm:-mx-6 lg:-mx-8"&gt;
                &lt;div class="inline-block min-w-full py-2 sm:px-6 lg:px-8"&gt;
                    &lt;div class="overflow-hidden"&gt;
                        &lt;table class="min-w-full text-left text-sm font-light"&gt;
                            &lt;thead class="border-b font-medium dark:border-neutral-500 dark:text-gray-100"&gt;
                                &lt;tr&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        &lt;div class="flex items-center"&gt;
                                            &lt;button wire:click="sortBy('id')"&gt;{{ __('ID') }}&lt;/button&gt;
                                            @if($sortBy=='id')
                                                @if($sortAsc)
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-up"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @else
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-down"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @endif
                                            @endif
                                        &lt;/div&gt;
                                    &lt;/th&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        &lt;div class="flex items-center"&gt;
                                            &lt;button wire:click="sortBy('title')"&gt;{{ __('Title') }}&lt;/button&gt;
                                            @if($sortBy=='title')
                                                @if($sortAsc)
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-up"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @else
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-down"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @endif
                                            @endif
                                        &lt;/div&gt;
                                    &lt;/th&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        &lt;div class="flex items-center"&gt;
                                            &lt;button wire:click="sortBy('is_active')"&gt;{{ __('Is active') }}&lt;/button&gt;
                                            @if($sortBy=='is_active')
                                                @if($sortAsc)
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-up"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @else
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-down"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @endif
                                            @endif
                                        &lt;/div&gt;
                                    &lt;/th&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        &lt;div class="flex items-center"&gt;
                                            &lt;button wire:click="sortBy('type')"&gt;{{ __('Type') }}&lt;/button&gt;
                                            @if($sortBy=='type')
                                                @if($sortAsc)
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-up"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @else
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-down"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @endif
                                            @endif
                                        &lt;/div&gt;
                                    &lt;/th&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        &lt;div class="flex items-center"&gt;
                                            &lt;button wire:click="sortBy('created_at')"&gt;{{ __('Created at') }}&lt;/button&gt;
                                            @if($sortBy=='created_at')
                                                @if($sortAsc)
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-up"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @else
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-down"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @endif
                                            @endif
                                        &lt;/div&gt;
                                    &lt;/th&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        &lt;div class="flex items-center"&gt;
                                            &lt;button wire:click="sortBy('updated_at')"&gt;{{ __('Updated at') }}&lt;/button&gt;
                                            @if($sortBy=='updated_at')
                                                @if($sortAsc)
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-up"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @else
                                                 &lt;span class="ml-2"&gt;&lt;i class="fas fa-sort-down"&gt;&lt;/i&gt;&lt;/span&gt;
                                                @endif
                                            @endif
                                        &lt;/div&gt;
                                    &lt;/th&gt;
                                    &lt;th scope="col" class="px-6 py-4"&gt;
                                        {{ __('Actions') }}
                                    &lt;/th&gt;
                                &lt;/tr&gt;
                            &lt;/thead&gt;
                            &lt;tbody&gt;
                                @forelse($items as $item)
                                    &lt;tr class="border-b transition duration-300 ease-in-out dark:text-gray-100 hover:bg-neutral-100 dark:border-neutral-500 dark:hover:bg-neutral-600 dark:hover:text-gray-200"&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4 font-medium"&gt;{{ $item-&gt;id }}&lt;/td&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4"&gt;{{ $item-&gt;title }}&lt;/td&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4"&gt;{{ $item-&gt;is_active ? __('Yes') : __('No') }}&lt;/td&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4"&gt;{{ $item-&gt;type-&gt;value }}&lt;/td&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4"&gt;{{ $item-&gt;created_at-&gt;diffForHumans() }}&lt;/td&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4"&gt;{{ $item-&gt;updted_at?-&gt;diffForHumans() }}&lt;/td&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4"&gt;
                                            &lt;a href="{{ route('example-items.show', ['language' =&gt; app()-&gt;getLocale(), 'example_item' =&gt; $item-&gt;id]) }}" class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150"&gt;
                                                {{ __('Show') }}
                                            &lt;/a&gt;
                                            &lt;x-button wire:click="confirmItemEdit( {{ $item-&gt;id }})" class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150"&gt;
                                                {{ __('Edit') }}
                                            &lt;/x-button&gt;
                                            &lt;x-danger-button wire:click="confirmItemDeletion({{ $item-&gt;id }})" wire:loading.attr="disabled"&gt;
                                                {{ __('Delete') }}
                                            &lt;/x-danger-button&gt;
                                        &lt;/td&gt;
                                    &lt;/tr&gt;
                                @empty
                                    &lt;tr class="border-b transition duration-300 ease-in-out dark:text-gray-100 hover:bg-neutral-100 dark:border-neutral-500 dark:hover:bg-neutral-600 dark:hover:text-gray-200"&gt;
                                        &lt;td class="whitespace-nowrap px-6 py-4 font-medium"&gt;
                                            {{ __('No item found') }}
                                        &lt;/td&gt;
                                    &lt;/tr&gt;
                                @endforelse
                            &lt;/tbody&gt;
                        &lt;/table&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="mt-4"&gt;
        {{ $items-&gt;links() }}
    &lt;/div&gt;

    &lt;x-dialog-modal wire:model="confirmingItemAdd"&gt;
        &lt;x-slot name="title"&gt;
            {{ isset( $this-&gt;item['id']) ? 'Edit Item' : 'Add Item'}}
        &lt;/x-slot&gt;

        &lt;x-slot name="content"&gt;
            &lt;div class=""&gt;
                &lt;x-label for="title" value="{{ __('Title') }}" /&gt;
                &lt;x-input id="title" type="text" wire:model.defer="item.title" class="mt-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" /&gt;
                &lt;x-input-error for="item.title" class="mt-2" /&gt;
            &lt;/div&gt;

            &lt;div class="mt-4"&gt;
                &lt;x-label for="body" value="{{ __('Body') }}" /&gt;
                &lt;textarea wire:model.defer="item.body"
                    id="body"
                    class="block mt-2 p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
                    rows="4"&gt;&lt;/textarea&gt;
                &lt;x-input-error for="item.body" class="mt-2" /&gt;
            &lt;/div&gt;

            &lt;div class="mt-4"&gt;
                &lt;div class="flex items-center justify-start"&gt;
                    &lt;x-input wire:model.defer="item.is_active" id="is-active" type="checkbox" value="" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" /&gt;
                    &lt;x-label for="is-active" value="{{ __('Is active') }}" class="ml-2" /&gt;
                &lt;/div&gt;
                &lt;x-input-error for="item.is_active" class="mt-2" /&gt;
            &lt;/div&gt;

            &lt;div class="mt-4"&gt;
                &lt;x-label for="type" value="{{ __('Type') }}" /&gt;
                &lt;select wire:model.defer="item.type" id="type" class="mt-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"&gt;
                    &lt;option selected&gt;{{ __('Choose a type') }}&lt;/option&gt;
                    @foreach ($exampleItemTypes as $exampleItemType)
                        &lt;option value="{{ $exampleItemType['value'] }}"&gt;
                            {{ $exampleItemType['name'] }}
                        &lt;/option&gt;
                    @endforeach
                &lt;/select&gt;
                &lt;x-input-error for="item.type" class="mt-2" /&gt;
            &lt;/div&gt;
        &lt;/x-slot&gt;

        &lt;x-slot name="footer"&gt;
            &lt;x-secondary-button wire:click="$set('confirmingItemAdd', false)" wire:loading.attr="disabled"&gt;
                {{ __('Nevermind') }}
            &lt;/x-secondary-button&gt;
 
            &lt;x-button class="ml-2 bg-blue-500 hover:bg-blue-700" wire:click="saveItem()" wire:loading.attr="disabled"&gt;
                {{ __('Save') }}
            &lt;/x-button&gt;
        &lt;/x-slot&gt;
    &lt;/x-dialog-modal&gt;

    &lt;x-confirmation-modal wire:model="confirmingItemDeletion"&gt;
        &lt;x-slot name="title"&gt;
            {{ __('Delete Item') }}
        &lt;/x-slot&gt;
 
        &lt;x-slot name="content"&gt;
            {{ __('Are you sure you want to delete Item? ') }}
        &lt;/x-slot&gt;
 
        &lt;x-slot name="footer"&gt;
            &lt;x-secondary-button wire:click="$set('confirmingItemDeletion', false)" wire:loading.attr="disabled"&gt;
                {{ __('Nevermind') }}
            &lt;/x-secondary-button&gt;
 
            &lt;x-danger-button class="ml-2" wire:click="deleteItem({{ $confirmingItemDeletion }})" wire:loading.attr="disabled"&gt;
                {{ __('Delete') }}
            &lt;/x-danger-button&gt;
        &lt;/x-slot&gt;
    &lt;/x-confirmation-modal&gt;
&lt;/div&gt;
Testing Livewire Component
Testing is a crucial part of software development and Livewire is no exception. Laravel provides excellent testing tools that we can also use when testing our Livewire components.
For testing Livewire components, we can use Laravel's testing framework PHPUnit. Laravel provides a test() method, which we can use to create test cases for our components. However, as I am an advocate of simplicity and prefer more readable code, we will use the Pest package (with the use of a plugin for Livewire). After its installation, the component test might look like this:
&lt;?php

use App\Enums\Examples\ExampleItemType;
use App\Models\Examples\ExampleItem;
use Livewire\Livewire;

it('can render the livewire item manager component', function () {
    Livewire::test('examples.example-item-manager')
        -&gt;assertStatus(200);
});

it('can add new item', function () {
    Livewire::test('examples.example-item-manager')
        -&gt;set('item.title', 'Test item')
        -&gt;set('item.body', 'Test body')
        -&gt;set('item.is_active', true)
        -&gt;set('item.type', ExampleItemType::TYPE2-&gt;value)
        -&gt;call('saveItem')
        -&gt;assertSee('Test item');
});

it('can edit existing item', function () {
    $item = ExampleItem::factory()-&gt;create();

    Livewire::test('examples.example-item-manager')
        -&gt;call('confirmItemEdit', $item-&gt;id)
        -&gt;set('item.title', 'Test edit')
        -&gt;call('saveItem')
        -&gt;assertSee('Test edit');
});

it('can delete an existing item', function () {
    $item = ExampleItem::factory()-&gt;create();

    Livewire::test('examples.example-item-manager')
        -&gt;call('confirmItemDeletion', $item-&gt;id)
        -&gt;call('deleteItem', $item-&gt;id)
        -&gt;assertDontSee($item-&gt;title);
});

it('can search for items', function () {
    $item1 = ExampleItem::factory()-&gt;create(['title' =&gt; 'First Item']);
    $item2 = ExampleItem::factory()-&gt;create(['title' =&gt; 'Second Item']);

    Livewire::test('examples.example-item-manager')
        -&gt;set('q', 'First')
        -&gt;assertSee($item1-&gt;title)
        -&gt;assertDontSee($item2-&gt;title);
});

it('can sort items', function () {
    $item1 = ExampleItem::factory()-&gt;create(['title' =&gt; 'First Item']);
    $item2 = ExampleItem::factory()-&gt;create(['title' =&gt; 'Second Item']);

    $component = Livewire::test('examples.example-item-manager');

    // sorting is ascending
    $component-&gt;set('sortBy', 'title')-&gt;set('sortAsc', true)-&gt;call('render');
    $this-&gt;assertEquals([$item1-&gt;id, $item2-&gt;id], $component-&gt;viewData('items')-&gt;pluck('id')-&gt;toArray());

    // now sort descending
    $component-&gt;set('sortBy', 'title')-&gt;set('sortAsc', false)-&gt;call('render');
    $this-&gt;assertEquals([$item2-&gt;id, $item1-&gt;id], $component-&gt;viewData('items')-&gt;pluck('id')-&gt;toArray());
});
Testing is essential to ensure the quality of our code and to verify that our application works as it should. Laravel and Livewire provide all the tools we need to create robust and reliable tests for our applications.

In Conclusion
In this article, we have looked in detail at how to create a Livewire component in Laravel for CRUD operations including testing. We have gone through the basics of Laravel and Livewire, we have created a Livewire component, we have implemented CRUD operations, and we have learned how to test our component.
Important points that emerge from this tutorial are:

Laravel and Livewire are a powerful combination for web application development.
CRUD operations are basic operations that we can perform on our data.
Testing is essential to ensure the quality of our code and to verify that our application works as it should.

I hope this tutorial will help you create your own Livewire components and that it will inspire you to further explore the possibilities that Laravel and Livewire offer.]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/30/30de7f39-26e1-4988-a210-9525688d63b2/conversions/laravel-livewire-crud-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Laravel CRUD]]></title>
                <link>https://www.pavelzanek.com/en/blog/laravel-crud</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/laravel-crud</guid>
                <pubDate>Sat, 24 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Learn how to implement the basic data management operations – Create, Read, Update and Delete – in the Laravel framework and how to efficiently link them with the database and user interface.]]></description>
                
                                    <content:encoded><![CDATA[What is CRUD?
CRUD is a fundamental concept that is necessary for managing data in any web application. CRUD is an acronym for Create, Read, Update, and Delete. These four operations form the basic functions needed to interact with a database.

In Laravel, working with CRUD is made easier thanks to its ORM (Object-Relational Mapping) called Eloquent. Eloquent allows developers to work with database tables as objects and provides a simple interface (you could say API) for common database operations.

Creating (Create) in Laravel is done using the create() method, which creates a new record in the database. Reading (Read) is done using methods like get(), all(), find(), etc., which load records from the database. Updating (Update) is done using the update() method, which modifies an existing record in the database. And finally, deleting (Delete) is done using the delete() method, which removes a record from the database.

Introduction to our demonstration
Imagine that we want to create an ExampleItem model, which will contain these attributes:

title (string)
body (string / text)
is_active (boolean)
type (string)


Prerequisite is to have the Laravel framework installed. Since I tested this code on an already modified application, you will also find the localization of the application and the restriction of access to only users with the superadmin role.

The file structure is adapted for the demonstration, so in addition to the file names, I also specify the folder in which the file is located. However, the usage is entirely up to you, you can adjust the structure according to your needs.

The Pest package is then used as part of the testing.

Creating a migration
Migrations in Laravel are like a versioning system for your database. They allow you to change the database structure using PHP code instead of manually writing SQL. Migrations are also a great tool for sharing and updating the database structure among team members.

Creating a migration in Laravel is simple thanks to the Artisan command. The "php artisan make:migration" command creates a new migration file in the "database/migrations" directory. The file name contains the date and time of creation, which allows Laravel to determine in what order the migrations should be run.

Each migration file contains two methods: "up" and "down". The "up" method is used to add new tables, columns, or indexes to your database. The "down" method should perform the opposite operations to those performed in the "up" method.

After creating the migration, you can run the migration using the "php artisan migrate" command. This command runs all migrations that have not yet been run in the order they were created.

Migration (database/migrations):

&lt;?php

use App\Enums\Examples\ExampleItemType;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('example_items', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->mediumText('body')->nullable();
            $table->boolean('is_active')->default(false);
            $table->string('type', 8)->default(ExampleItemType::TYPE1->value);
            $table->timestamps();
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('example_items');
    }
};


Creating a model
Models are one of the key aspects of the framework. They are representations of database tables and allow you to work with database records as objects. This means that you can perform CRUD operations on your models without having to write SQL.

Creating a model in Laravel is simple. You use the Artisan command "php artisan make:model", which creates a new model in the "app/Models" directory. The model name should be in singular and start with a capital letter.

Each model in Laravel extends the "Illuminate\\Database\\Eloquent\\Model" class and contains methods that allow interaction with the database. You can also define your own methods and properties on your models.

Models also contain so-called Eloquent relationships, which allow you to define relationships between different models. For example, if you have a "User" model and a "Post" model, you can define a relationship that says that one user can have many posts.

"ExampleItem" Model (app\\Models\\Examples):

&lt;?php

namespace App\Models\Examples;

use App\Enums\Examples\ExampleItemType;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class ExampleItem extends Model
{
    use HasFactory;
    use SoftDeletes;

    protected $fillable = [
        'title',
        'body',
        'is_active',
        'type',
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'type' => ExampleItemType::class,
    ];
}


Creating actions
In Laravel, you can define actions as separate classes that represent individual operations that your application can perform. This is an alternative approach to the traditional model where actions are defined as methods in controllers.

Creating an action as a separate file in Laravel is simple. First, you need to create a new class in the "app/Actions" directory. The class, for example, can have an "execute()" method that performs the desired operation.

This approach has several advantages. One of them is that your actions are well isolated, easily extendable, and testable. Each action has a clearly defined responsibility and it's easy to test it independently of other parts of your application.

"CreateExampleItemAction" Action (app\\Actions\\Examples\\ExampleItems):

&lt;?php

namespace App\Actions\Examples\ExampleItems;

use App\Models\Examples\ExampleItem;

class CreateExampleItemAction
{
    public function execute(array $validatedData): ExampleItem
    {
        return ExampleItem::create($validatedData);
    }
}


"UpdateExampleItemAction" Action (app\\Actions\\Examples\\ExampleItems):

&lt;?php

namespace App\Actions\Examples\ExampleItems;

use App\Models\Examples\ExampleItem;

class UpdateExampleItemAction
{
    public function execute(ExampleItem $exampleItem, array $validatedData): ExampleItem
    {
        $exampleItem->update($validatedData);

        return $exampleItem;
    }
}


"RemoveExampleItemAction" Action (app\\Actions\\Examples\\ExampleItems):

&lt;?php

namespace App\Actions\Examples\ExampleItems;

use App\Models\Examples\ExampleItem;

class RemoveExampleItemAction
{
    public function execute(ExampleItem $exampleItem): void
    {
        $exampleItem->delete();
    }
}


Creating enum
Creating Enums in Laravel is a powerful way to define a type of variable that allows for many different, but specific values. This feature is particularly useful when you want to limit the possibilities of a variable's value, ensuring that it only holds a value from a specific set. In Laravel, Enums are not built-in, but they can be easily implemented using PHP classes.

Creating Enums in Laravel can be a great way to make your code more readable and maintainable, especially when dealing with variables that should only have a specific set of values. They can be used in various parts of your Laravel application, such as in models, controllers, and even in your database migrations.

In addition to making your code cleaner and easier to understand, Enums also help to reduce errors in your code. By limiting the possible values of a variable, you can ensure that it only ever holds a value that it's supposed to, reducing the likelihood of unexpected values causing bugs in your code.

Remember, Enums are just one of the many advanced features that Laravel offers to make your PHP development easier and more efficient. Whether you're building a small personal project or a large enterprise application, Laravel has the tools and features you need to build robust, scalable, and maintainable PHP applications.

"ExampleItemType" Enum (app\\Enums\\Examples):

&lt;?php

namespace App\Enums\Examples;

use Illuminate\Support\Collection;

enum ExampleItemType: string
{
    case TYPE1 = 'Type 1';
    case TYPE2 = 'Type 2';

    public static function all(): Collection
    {
        return collect(ExampleItemType::cases())->map(
            fn(ExampleItemType $code) => $code->details()
        );
    }

    public function details(): array
    {
        return match($this) 
        {
            self::TYPE1 => [
                'name'  => 'Type Name 1',
                'value' => 'Type 1',
            ],

            self::TYPE2 => [
                'name'  => 'Type Name 2',
                'value' => 'Type 2',
            ],
        };
    }
}


Creating validation / validation requests
Validation requests are special classes that serve to validate input data before they are processed by your application. Using validation requests, you can ensure that the data your application receives is always in the expected format and meets all the rules you have set.

Creating a validation request in Laravel is simple. First, you need to create a validation class using the Artisan command "php artisan make:request", which creates a new validation request in the "app/Http/Requests" directory.

The validation class contains two methods: "authorize()" and "rules()". The "authorize()" method determines whether the user is authorized to make the request. The "rules()" method then returns an array of validation rules that should be applied to the input data.

"StoreXYZRequest" and "UpdateXYZRequest" are two common types of validation requests in Laravel. "StoreXYZRequest" is used when creating a new record and "UpdateXYZRequest" is used when updating an existing record. However, you can, for example, create only one validation request that will be used when creating and editing a record - which is handy if the validation conditions for creating and editing are the same.

"StoreExampleItemRequest" Validation Request (app\\Http\\Requests\\Examples\\ExampleItems):

&lt;?php

namespace App\Http\Requests\Examples\ExampleItems;

use App\Enums\Examples\ExampleItemType;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;

class StoreExampleItemRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'title' => 'required|string|max:255',
            'body' => 'nullable|string',
            'is_active' => 'required|boolean',
            'type' => [
                'required',
                'string',
                'max:8',
                new Enum(ExampleItemType::class),
            ],
        ];
    }

    protected function prepareForValidation()
    {
        $this->merge([
            'is_active' => $this->has('is_active') ? true : false,
        ]);
    }
}


"UpdateExampleItemRequest" Validation Request (app\\Http\\Requests\\Examples\\ExampleItems):

&lt;?php

namespace App\Http\Requests\Examples\ExampleItems;

use App\Enums\Examples\ExampleItemType;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;

class UpdateExampleItemRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'title' => 'required|string|max:255',
            'body' => 'nullable|string',
            'is_active' => 'required|boolean',
            'type' => [
                'required',
                'string',
                'max:8',
                new Enum(ExampleItemType::class),
            ],
        ];
    }

    protected function prepareForValidation()
    {
        $this->merge([
            'is_active' => $this->has('is_active') ? true : false,
        ]);
    }
}


Creating a controller
Controllers are a key part of any application built on this framework. They are classes that handle all HTTP requests that your application receives and control how your application should respond.

Creating a controller in Laravel is simple again thanks to the Artisan tool, which is part of Laravel. The "php artisan make:controller" command creates a new controller in the "app/Http/Controllers" directory. The controller name should be in singular and start with a capital letter.

Controllers in Laravel can either be simple, which are controllers with one action (uses the "__invoke" method), or resource, which are controllers that handle a whole set of CRUD operations. Resource controllers are ideal for working with database records, such as users, blog posts, or any other entities in your application. Of course, a controller can also be created according to your ideas, so it does not have to be either with one method, nor a resource one.

"ExampleItemController" Controller (app\\Http\\Controllers\\Examples):

&lt;?php

namespace App\Http\Controllers\Examples;

use App\Actions\Examples\ExampleItems\CreateExampleItemAction;
use App\Actions\Examples\ExampleItems\RemoveExampleItemAction;
use App\Actions\Examples\ExampleItems\UpdateExampleItemAction;
use App\Enums\Examples\ExampleItemType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Examples\ExampleItems\StoreExampleItemRequest;
use App\Http\Requests\Examples\ExampleItems\UpdateExampleItemRequest;
use App\Models\Examples\ExampleItem;

class ExampleItemController extends Controller
{
    public function index()
    {
        $exampleItems = ExampleItem::orderBy('created_at', 'desc')->paginate(20);
        return view('examples.example-items.index', ['exampleItems' => $exampleItems]);
    }

    public function create()
    {
        return view('examples.example-items.create', ['exampleItemTypes' => ExampleItemType::all()]);
    }

    public function store(StoreExampleItemRequest $request)
    {
        (new CreateExampleItemAction())->execute($request->validated());
        return redirect()->route('example-items.index')->with(['flashType' => 'success', 'flashMessage' => __('Example Item was successfully created.')]);
    }

    public function show(ExampleItem $exampleItem)
    {
        abort_if(!$exampleItem->is_active, 404, "Example Item is not active.");
        return view('examples.example-items.show', ['exampleItem' => $exampleItem]);
    }

    public function edit(ExampleItem $exampleItem)
    {
        return view('examples.example-items.edit', ['exampleItem' => $exampleItem, 'exampleItemTypes' => ExampleItemType::all()]);
    }

    public function update(UpdateExampleItemRequest $request, ExampleItem $exampleItem)
    {
        (new UpdateExampleItemAction())->execute($exampleItem, $request->validated());
        return redirect()->route('example-items.index')->with(['flashType' => 'success', 'flashMessage' => __('Example Item was successfully updated.')]);
    }

    public function destroy(ExampleItem $exampleItem)
    {
        (new RemoveExampleItemAction())->execute($exampleItem);
        return redirect()->route('example-items.index')->with(['flashType' => 'success', 'flashMessage' => __('Example Item was successfully removed.')]);
    }
}


Creating a template
Templates are a key tool for creating dynamic web pages. Laravel uses the "Blade" template engine, which allows you to insert PHP code directly into HTML templates.

Creating a template in Laravel is simple. First, you need to create a template file in the "resources/views" directory. Template files have a ".blade.php" extension.

Templates can contain any valid HTML code as well as special Blade directives for inserting PHP code. For example, you can use the directive "{{ $variable }}" to output the value of a variable, or directives @if, @foreach, and others to control the flow of the application.

In addition, you can use the template inheritance system, which allows you to define "base" templates with a general page structure and then create "inherited" templates that extend this structure and add specific content.

[Index, Create, Edit, Show Blade templates as fully fetched above]

Routing
Routing is one of the most important aspects of any web application, and Laravel provides a powerful and flexible routing system that makes it easy to define routes for your application.

Routes in Laravel are defined in route files, which are located in the "routes" directory of your application. Laravel provides several different route files for different types of routes, including web routes, API routes, and console routes.

Each route is defined using an HTTP method (such as GET, POST, PUT, or DELETE), a path, and an action to be performed when the route is invoked. The action can be either a function (closure function), or a reference to a controller method.

Laravel also supports advanced routing features such as wildcard routing, named routing, middleware routing, parameter constraint routing, and so on.

Routing for "web" (routes):

...
Route::group([
    'prefix' => "{language}", 
    'where' => ['language' => '[a-zA-Z]{2}']
    ], function () {

    // Admin
    Route::group(['middleware' => ['role:superadmin']], function () {
        ...
        Route::resource('/examples/example-items', ExampleItemController::class);
    });

});
...


Creating a factory
Factories are tools that make it easy to generate test data for your database. Factories allow you to define "templates" (not to be confused with blade templates) for creating new instances of your models with random or predefined data.

Creating a factory in Laravel is simple again thanks to Artisan. The "php artisan make:factory" command creates a new factory in the "database/factories" directory. The name of the factory should correspond to the name of the model for which the factory is intended.

Each factory contains a "definition()" method, which returns an array of attributes to be used when creating a new instance of the model. You can use Laravel functions like "faker" to generate random data.

Factories are ideal for creating large amounts of data for testing or for populating your database before development or during development.

"ExampleItemFactory" Factory (database/factories/Examples):

&lt;?php

namespace Database\Factories\Examples;

use App\Enums\Examples\ExampleItemType;
use App\Models\Examples\ExampleItem;
use Illuminate\Database\Eloquent\Factories\Factory;

class ExampleItemFactory extends Factory
{
    protected $model = ExampleItem::class;

    public function definition()
    {
        return [
            'title' => $this->faker->sentence(4),
            'body' => $this->faker->realText(500),
            'is_active' => $this->faker->boolean(),
            'type' => $this->faker->boolean() ? ExampleItemType::TYPE1 : ExampleItemType::TYPE2,
        ];
    }
}


Creating tests
Testing is a fundamental part of developing any application, and Laravel provides excellent tools for automated testing of your code. Laravel allows you to easily create and run tests for your application.

Creating a test in Laravel is simple, as you might expect, thanks to the Artisan tool. The "php artisan make:test" command creates a new test in the "tests/Feature" or "tests/Unit" directory, depending on what type of test you want to create.

Each test is a class that contains one or more test methods. These methods contain assertions that verify that your code is working as it should. Laravel provides a wide range of assertions to verify various aspects of your application, including HTTP responses, database interactions, and much more.

You can run tests using the "php artisan test" command, which runs all tests in your application and prints the results to the console.

Tests for the controller
"ExampleItemControllerTest" Test (tests/Feature/App/Controllers/Examples):

[full Pest controller test code as fetched above]

Tests for actions
"CreateExampleItemActionTest", "UpdateExampleItemActionTest", "RemoveExampleItemActionTest" Tests (tests/Feature/App/Actions/Examples/ExampleItems):

[full Pest action test code as fetched above]

Conclusion
In this tutorial, we have thoroughly familiarized ourselves with the process of creating CRUD operations in Laravel. We have gone through all the key steps, from creating migrations and models, through defining actions and validation requests, to creating templates, factories, and tests. I hope this tutorial has helped you understand how to work with Laravel and has provided you with a solid foundation for further development of your own applications.]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/02/0259a2c3-ce08-4aaf-bafb-408abf6f2386/conversions/laravel-crud-full.png" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[ChatGPT&#039;s Browse with Bing: From SEO to AI Optimization]]></title>
                <link>https://www.pavelzanek.com/en/blog/seo-ai-optimization-chatgpt-browse-with-bing</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/seo-ai-optimization-chatgpt-browse-with-bing</guid>
                <pubDate>Thu, 22 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[The article explores ChatGPT&#039;s ability to &quot;read&quot; websites using &quot;Browse with Bing&quot; and the importance of shifting from SEO to AI optimization for websites.]]></description>
                
                                    <content:encoded><![CDATA[Welcome to a new world where artificial intelligence is becoming increasingly advanced and offering us limitless possibilities. One of these exciting developments is ChatGPT, an artificial intelligence model developed by OpenAI. But what if I told you that ChatGPT can now "read" your website using a feature called "Browse with Bing"? Yes, you heard right. This article delves into this fascinating feature and how it can change the way we interact with the internet and how we will adapt SEO on the web so that one of the possible answers in ChatGPT are links to your websites.
ChatGPT is an advanced chatbot that uses the GPT (Generative Pretrained Transformer) language model to generate compelling texts. Since its market launch, it has become one of the most popular tools for generating text, thanks to its ability to create naturally sounding responses to various queries. You can read more about ChatGPT in one of the older articles I prepared for you.
Now, with the advent of the "Browse with Bing" feature, ChatGPT's capabilities are expanding even further. "Browse with Bing" is a feature that allows ChatGPT to access information on the web in real-time. This means that ChatGPT can now provide current and relevant answers to your queries by "browsing" the internet.
What is the "Browse with Bing" feature?
"Browse with Bing" is an innovative tool (currently this feature is labeled as a Beta version in ChatGPT), which was recently introduced as part of ChatGPT. This feature allows ChatGPT to access the internet in real-time and provide current and relevant answers to user queries. But how exactly does it work?
"Browse with Bing" is essentially a plugin that connects ChatGPT with the Bing search engine. When a user enters a query, ChatGPT uses Bing to search for relevant information on the web/internet.
One of the key advantages of the "Browse with Bing" feature is its ability to provide current information. While ChatGPT is trained on a static dataset that is updated only occasionally, "Browse with Bing" allows ChatGPT to access the latest information on the web. This means it can provide answers to questions about current events, new research, and other rapidly changing topics.
"Browse with Bing" is also very flexible. It can be used for a wide range of queries, from simple factual questions to complex queries. Whether you need to find out the current weather, find the latest research in a certain field, or get information about a specific product, "Browse with Bing" can help you find the answers.
How does ChatGPT "read" websites using the "Browse with Bing" feature?
The process by which ChatGPT "reads" websites using the "Browse with Bing" feature is a fascinating combination of advanced technologies. This process begins when a user enters a query. ChatGPT then uses Bing to search for relevant information on the web. This search is done in real-time, which means that the information that ChatGPT provides is current and relevant.
Once Bing finds the corresponding websites, ChatGPT reads these sites by analyzing their content and extracting key information from them. This process is possible thanks to the sophisticated natural language processing algorithms that ChatGPT uses. These algorithms allow ChatGPT to understand the text on websites as well as a human would.
After extracting the key information, ChatGPT processes this information and creates a response to the user's query. This response is then displayed to the user. The entire process takes place within a few seconds, which means that users can get answers to their queries almost instantly. In the responses, you can notice links from which ChatGPT, or this feature, drew:

It's important to note that although ChatGPT browseswebsites, it does not store any information from these sites. Once the response to the user's query is generated, all information obtained from the websites is discarded. This means that ChatGPT respects users' privacy and does not store any personal data.
SEO and ChatGPT with Browse with Bing
In the field of web development and marketing, we are witnessing a fascinating shift. Previously, we focused on search engine optimization (SEO), but now the era is coming when it is necessary to optimize websites for artificial intelligence. This shift is a result of rapid technological development and the growing influence of artificial intelligence on our daily lives.
In the past, search engine optimization (SEO) was a key strategy for increasing website visibility. SEO focuses on using keywords, quality content, and other techniques to improve positions in search results, such as Google. This practice is still important, but with the advent of artificial intelligence, the rules of the game are changing.
Artificial intelligence (AI) is capable of analyzing and processing a huge amount of data faster and more efficiently than any human. This allows AI to provide more accurate and personalized experiences for users. For example, AI can analyze user behavior on the web, their interests and preferences, and based on this information, recommend relevant content or products.
Therefore, it is now important to optimize websites for artificial intelligence. This means creating websites that are AI-friendly, which includes clear and structured information that can be easily processed by AI, and creating content that is relevant and useful to users.
Optimizing websites for AI can involve various techniques, including using AI tools to analyze and improve content, using AI to personalize the user experience, using AI to analyze and improve SEO strategies, and much more.
The development of technologies and the growing influence of artificial intelligence on web development and marketing present exciting new possibilities. As technologies continue to evolve, it is clear that optimizing websites for AI will play an increasingly important role in the future of web development and marketing.
How to find out if ChatGPT with the "Browse with Bing" feature has been able to browse your websites?
So let's take a look at a small guide on how to verify that ChatGPT with the Browse with Bing feature has been able to browse your websites. The way to find this out is very simple. Just use this feature and ask about the specific URL that interests us. First, however, let's show what ChatGPT can display if it is not able (or the Browse with Bing feature) to browse websites:

As you can notice, if the algorithm is unable to browse websites, we will see "Reading content failed".
Now let's look at how to find out if ChatGPT can browse your websites. For the demonstration, I will use this personal blog.

As you can see, website analysis is easy. However, this process is manual. I think it's a matter of time before tools emerge that will do this process automatically.
Conclusion
As we learned in this article, ChatGPT and the "Browse with Bing" feature represent a breakthrough in the field of artificial intelligence and internet browsing. Thanks to ChatGPT's ability to "read" websites in real-time, we can get current and relevant answers to our queries faster and more efficiently than ever before.
This technology has enormous potential for the future. With the development of artificial intelligence and machine learning, we can expect the capabilities of ChatGPT and "Browse with Bing" to continue to develop and improve. This could lead to even faster and more accurate searching for information on the internet, which could help us better understand the world around us.
In conclusion, I would like to thank you for your interest in this fascinating topic. I hope this article has provided you with useful and interesting information about ChatGPT and the "Browsewith Bing" feature. I will continue to explore this topic and update the article with new information. If you have any comments, feel free to write to me. I look forward to exploring the world of artificial intelligence and SEO with you!]]></content:encoded>
                
                                    <category><![CDATA[Artificial Intelligence]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/89/896f4c93-d457-4e30-b5d2-668db8f77f7a/conversions/seo-chatgpt-browse-with-bing-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[How to create a newsletter system in Laravel]]></title>
                <link>https://www.pavelzanek.com/en/blog/laravel-newsletter</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/laravel-newsletter</guid>
                <pubDate>Wed, 21 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Learn how to build a newsletter system in Laravel from scratch. This comprehensive guide covers everything from creating subscriptions to sending emails.]]></description>
                
                                    <content:encoded><![CDATA[How to effectively build a newsletter sign-up system in Laravel: from basics to testing

Welcome to this extensive guide where we'll look at how to effectively create a newsletter subscription system in Laravel. Laravel is a robust and flexible PHP framework that is suitable for a wide range of applications, including the creation of a functional and customizable newsletter.

In today's era, newsletters are one of the most important tools for communication with customers or users of a website. Whether you provide updates, educational materials, or special offers, it is crucial that your newsletter subscription system is user-friendly and effective.

This guide will walk you through the entire process of creating such a system in Laravel, from the basic preparation of a database factory, through creating an email template and Livewire component, to routing settings. Last but not least, we will look at the importance of translations and internationalization, and how to achieve this in Laravel.

Of course, any development should be accompanied by quality testing, and so we will also focus on how to write effective tests using the Pest tool.

Database Factory Preparation

For working with data in Laravel, one of the prerequisites is to prepare a database factory that will provide us with a framework for manipulating data and allow us to work efficiently and safely with our database.

In this guide, we will work with one specific model - NewsletterUser. This model will represent individual users who subscribe to our newsletter.

The first step is to create a factory for our model. Although this procedure is not typical, it will give you a better idea of what the model will contain. The factory will allow us to generate test data for our purposes. With it, we will be able to easily create instances of our NewsletterUser model with randomly generated data, which will come in handy during the final testing.

In Laravel, creating a factory is very simple. Just use the Artisan command make:factory, which automatically generates the factory skeleton for our model.

php artisan make:factory NewsletterUserFactory --model=NewsletterUser

This will create a new NewsletterUserFactory class that we will then modify for our needs. In our case, at least the following attributes will need to be set: email, language, verification_token, and is_verified.

The resulting class could look like this:

&lt;?php

namespace Database\Factories\Newsletter;

use App\Enums\Newsletter\NewsletterLanguage;
use App\Models\Newsletter\NewsletterUser;
use Illuminate\Database\Eloquent\Factories\Factory;

class NewsletterUserFactory extends Factory
{
    protected $model = NewsletterUser::class;

    public function definition()
    {
        return [
            'email' => $this->faker->email(),
            'language' => NewsletterLanguage::ENGLISH,
            'is_verified' => false,
        ];
    }
}

This factory now allows us to create test instances of our NewsletterUser model with random data. This will come in handy during the further development and testing of our newsletter subscription system.

Database Migration

Migration is a key part of Laravel that allows us to create the structure of our database directly from our code. Let's create a migration using the artisan command:

php artisan make:migration create_newsletter_users_table

In our case, we created a migration for the NewsletterUser model, which contains all the necessary information for managing newsletter subscribers, such as email, language, and verification status.

&lt;?php

use App\Enums\Newsletter\NewsletterLanguage;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('newsletter_users', function (Blueprint $table) {
            $table->id();
            $table->string('email', 128)->unique();
            $table->string('language', 6)->default(NewsletterLanguage::ENGLISH->value);
            $table->boolean('is_verified')->default(false);
            $table->string('verification_token', 60)->nullable();
            $table->timestamps();
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('newsletter_users');
    }
};

Thanks to migration, we can easily create, modify, and delete database tables, which is very useful during application development and distribution among different environments. Moreover, Laravel automatically keeps track of which migrations have already been applied, so we don't have to deal with their repeated execution.

Creating an Email Template

When a user enters their email and selects the preferred language of the newsletter, we need to send them a verification email. It contains a verification link that the user has to click on to verify their email. For this purpose, we will need to create an email template.

Laravel again offers very convenient work with email templates. We start by creating a new class for our email notification using the Artisan command:

php artisan make:mail NewsletterVerificationMail --markdown=emails.newsletter-verification

With this command, we created a new NewsletterVerificationMail class and at the same time told Laravel that we want to use markdown format to create our email template. Laravel automatically created a file for this template in the resources/views/emails directory.

We can now modify this template to suit our needs. In our case, for demonstration purposes, we need to display several pieces of information in the email:


Welcome message
Verification link
Button to redirect to our website


The resulting template could look like this:

&lt;x-mail::message&gt;
# {{ __('template.newsletter-email-verification-headline') }}

{{ __('template.newsletter-email-verification-description') }}
 
&lt;x-mail::button :url="$signedUrl"&gt;
    {{ __('template.newsletter-email-verification-verify-button') }}
&lt;/x-mail::button&gt;

&lt;x-mail::button :url="$homepageUrl"&gt;
    {{ __('template.newsletter-email-verification-homepage-button') }}
&lt;/x-mail::button&gt;
 
{{ __('template.newsletter-email-verification-thanks') }},&lt;br&gt;
{{ config('app.name') }}
&lt;/x-mail::message&gt;

In this template, we used Laravel's mail::message and mail::button components, which allow us to easily create the structure of our email. The texts are loaded from translation files, so we can easily switch between different languages according to the user's choice.

Finally, we need to use this template in our NewsletterVerificationMail class:

&lt;?php

namespace App\Mail\App\Guest\Newsletter;

use App\Models\Newsletter\NewsletterUser;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\URL;

class NewsletterVerificationMail extends Mailable
{
    use Queueable, SerializesModels;

    public NewsletterUser $newsletterUser;

    public function __construct(NewsletterUser $newsletterUser)
    {
        $this->newsletterUser = $newsletterUser;
    }

    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: __('template.newsletter-email-verification-subject') . ' | PavelZanek.com',
        );
    }

    /**
     * Get the message content definition.
     *
     * @return \Illuminate\Mail\Mailables\Content
     */
    public function content()
    {
        $signedUrl = URL::signedRoute('newsletter.verify-user', [
            'language' => $this->newsletterUser->language,
            'token' => $this->newsletterUser->verification_token
        ]);

        return new Content(
            markdown: 'emails.app.guest.newsletter.verification-mail',
            with: [
                'newsletterUser' => $this->newsletterUser,
                'signedUrl' => $signedUrl,
                'homepageUrl' => route('homepage', ['language' => 'en']),
            ],
        );
    }
}

There is no need to discuss the code sample in more detail here, we will use the provided data and set the subject of the email.

Creating a Livewire Component

Livewire is an excellent tool for creating dynamic components in Laravel, allowing for an easy connection between JavaScript and PHP. Its main advantage is that it does not require knowledge of JavaScript and everything can be solved directly in PHP.

In our case, we will use a Livewire component to create a form for newsletter subscription.

First, we create a new Livewire component using the Artisan command:

php artisan make:livewire NewSubscriberForm

This will create two new files - NewSubscriberForm.php and new-subscriber-form.blade.php. The first one is a class where we define the logic of the component. The second one is a template that describes what the component looks like.

In the NewSubscriberForm.php class, we define two public attributes - $email and $language, which represent the values entered by the user in our form. Furthermore, we need to create a subscribe() method, which will be called after the form submission.

&lt;?php

namespace App\Http\Livewire\Guest\Newsletter;

use App\Actions\Guest\Newsletter\CreateNewsletterUserAction;
use App\Enums\Newsletter\NewsletterLanguage;
use App\Mail\App\Guest\Newsletter\NewsletterVerificationMail;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\Rules\Enum;
use Livewire\Component;

class NewSubscriberForm extends Component
{
    public string $email = '';
    public string $language = '';

    public function render()
    {
        return view('livewire.guest.newsletter.subscription-form');
    }

    public function subscribe()
    {
        $validatedData = $this->validate([
            'email' => 'required|email|max:128|unique:newsletter_users,email',
            'language' => [
                'required',
                'string',
                'max:6',
                new Enum(NewsletterLanguage::class),
            ],
        ]);

        $newsletterUser = (new CreateNewsletterUserAction())->execute($validatedData);

        // Send verification email
        Mail::to($this->email)
            ->locale($this->language)
            ->send(new NewsletterVerificationMail($newsletterUser));

        $this->reset('email');

        $this->dispatchBrowserEvent('alert',[
            'type'=> 'success',
            'message'=> __('template.newsletter-waiting-for-validation')
        ]);
    }
}

In the subscribe() method, we check if the input data is valid. If not, Livewire will automatically display error messages in our template.

Finally, in the new-subscriber-form.blade.php file, we create our form template:

&lt;div&gt;
    &lt;div class="items-top mb-3 space-y-4 sm:flex sm:space-y-0 max-w-4xl"&gt;
        &lt;div class="relative w-full mr-1"&gt;
            &lt;label for="newsletter_email" class="hidden mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"&gt;
                {{ __('template.newsletter-email-label') }}
            &lt;/label&gt;
            &lt;div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none"&gt;
                &lt;svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"&gt;&lt;/path&gt;&lt;path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/div&gt;
            &lt;input wire:model.defer="email" class="block p-3 pl-10 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 sm:rounded-none sm:rounded-l-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-white dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="{{ __('template.newsletter-email-placeholder') }}" type="email" id="newsletter_email"&gt;
            @error('email')
                &lt;p class='mt-2 text-sm text-red-600'&gt;{{ $message }}&lt;/p&gt;
            @enderror
        &lt;/div&gt;
        &lt;div class="relative w-full md:w-80 mr-1"&gt;
            &lt;label for="newsletter_language" class="hidden mb-2 text-sm font-medium text-gray-900 dark:text-gray-300"&gt;
                {{ __('template.newsletter-language-label') }}
            &lt;/label&gt;
            &lt;select wire:model.defer="language" id="newsletter_language" class="bg-gray-50 border border-gray-300 text-gray-900 rounded-lg text-sm focus:ring-blue-500 focus:border-blue-500 block w-full p-3 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"&gt;
                @foreach (config('app.locales') as $lang => $language)
                    &lt;option value="{{ $lang }}"&gt;{{ __('template.' . $lang) }}&lt;/option&gt;
                @endforeach
            &lt;/select&gt;
            @error('language')
                &lt;p class='mt-2 text-sm text-red-600'&gt;{{ $message }}&lt;/p&gt;
            @enderror
        &lt;/div&gt;
        &lt;div&gt;
            &lt;button wire:click="subscribe()" wire:loading.attr="disabled" type="submit" class="py-3 px-5 w-full text-sm font-medium text-center text-white rounded-lg border cursor-pointer bg-primary-700 border-primary-600 sm:rounded-none sm:rounded-r-lg hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"&gt;
                {{ __('template.newsletter-subscribe-button') }}
            &lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

This code defines a form for entering email and selecting language. We use the wire:model command here, which allows us for two-way database binding between PHP and HTML. We also use wire:submit.prevent="subscribe" to submit the form and call our subscribe() method.

And that's all we need to create our Livewire component. How to integrate it into the page and further steps can be found below.

Implementing Livewire Component into the Template

Using a Livewire component in your Laravel application is straightforward and easy. In your Blade templating file, you simply use the @livewire directive. This directive accepts as the first parameter the name of the Livewire component you want to insert, and as the second parameter, you can pass an array with the data you want to pass to the component.

&lt;section class="mb-4 md:mb-8"&gt;
    &lt;div class="mx-auto"&gt;

        &lt;h2 class="mb-2 text-xl tracking-tight font-extrabold text-gray-900 sm:text-2xl dark:text-white"&gt;
            {{ __('template.newsletter-headline') }}
        &lt;/h2&gt;
        &lt;p class="mx-auto mb-2 font-light text-gray-500 sm:text-xl dark:text-gray-400"&gt;
            {{ __('template.newsletter-description') }}
        &lt;/p&gt;

        @livewire('guest.newsletter.new-subscriber-form', ['language' => app()->getLocale()])

    &lt;/div&gt;
&lt;/section&gt;

In the example guest.newsletter.new-subscriber-form is the name of our component and ['language' => app()->getLocale()] is the data we are passing to the component - specifically, the language the user is currently on. Thanks to this simple notation, we can easily use the component anywhere in your project.

Setting Up Routing

Routing is a key element of any web application. Laravel provides great support for defining routes for your applications.

In our case, we only need to define one route:


A route for user email address verification.


We define the route in the routes/web.php file.

...
Route::group([
    'prefix' => "{language}", 
    'where' => ['language' => '[a-zA-Z]{2}']
    ], function () {

    Route::get('/newsletter/verify/{token}', [NewsletterUserController::class, 'verify'])
        ->name('newsletter.verify-user')
        ->middleware('signed');

});
...

Note: It would be possible to use 2 routes - for user email address verification and a second route directly for the Livewire component.

In our case, we use the so-called signed route, which allows us to create links that are secure against "forgery". This route leads to the verify method in our NewsletterVerificationController.

Translations and Internationalization

Laravel provides a powerful tool for internationalizing your applications. Thanks to this, you can easily create applications that support multiple languages. For our newsletter system, we will need several translations.

Translations in Laravel are organized into files located in the resources/lang directory. Each language has its own directory and contains files with translations.

In our case, we will need translations for two languages, Czech and English. So, we create two files:


resources/lang/cs/template.php
resources/lang/en/template.php


In these files, we define the translations we will use in our newsletter subscription system. Each file contains an array, where the key represents the translation identifier and the value is the translation itself.

Sample for Czech translation:

&lt;?php

return [
    ...
    'newsletter-headline' => "Přihlašte se k odběru novinek",
    'newsletter-description' => "Přihlaste se k odběru novinek o AI, Laravelu, SEO a mnoho dalšího.",
    'newsletter-email-label' => "Email",
    'newsletter-email-placeholder' => "Zadejte svůj email",
    'newsletter-language-label' => "Jazyk",
    'newsletter-subscribe-button' => "Odebírat",
    'newsletter-waiting-for-validation' => "Na váš e-mailový účet byl odeslán ověřovací odkaz.",
    'newsletter-invalid-token' => "Neplatný token.",
    'newsletter-successfuly-verified' => "Úspěšně ověřeno.",
    'newsletter-email-verification-subject' => "Ověřte prosím svou emailovou adresu",
    'newsletter-email-verification-headline' => "Vítejte v mém Newsletteru!",
    'newsletter-email-verification-description' => "Děkujeme, že jste se přihlásili k odběru mého newsletteru. Kliknutím na tlačítko níže ověřte svou e-mailovou adresu a dokončete odebírání novinek.",
    'newsletter-email-verification-verify-button' => "Ověřit email",
    'newsletter-email-verification-homepage-button' => "Přejít na web",
    'newsletter-email-verification-thanks' => "Děkuji",
    ...
];

Sample for English translation:

&lt;?php

return [
    ...
    'newsletter-headline' => "Sign up for newsletter",
    'newsletter-description' => "Sign up for news on AI, Laravel, SEO and much more.",
    'newsletter-email-label' => "Email address",
    'newsletter-email-placeholder' => "Enter your email",
    'newsletter-language-label' => "Language",
    'newsletter-subscribe-button' => "Subscribe",
    'newsletter-waiting-for-validation' => "A verification link has been sent to your email account.",
    'newsletter-invalid-token' => "Invalid token.",
    'newsletter-successfuly-verified' => "Successfully verified.",
    'newsletter-email-verification-subject' => "Please verify your email address",
    'newsletter-email-verification-headline' => "Welcome to my Newsletter!",
    'newsletter-email-verification-description' => "Thank you for subscribing to my newsletter. Click the button below to verify your email address and complete your newsletter subscription.",
    'newsletter-email-verification-verify-button' => "Verify email",
    'newsletter-email-verification-homepage-button' => "Go to website",
    'newsletter-email-verification-thanks' => "Thanks",
    ...
];

We can then use these translations in our templates or code using the __helper - as already shown in the previous code parts.

In this way, we can add more languages to our application by simply adding more translation files. Laravel will automatically choose the right language according to the application settings (which is not the topic of this article).

System Testing Using Pest

Once we have a system for signing up users to the newsletter, it is important to make sure that all its parts are working properly. This is where automated tests come in.

Pest is a popular tool for testing in Laravel. Pest is an elegant wrapper over PHPUnit, which allows writing tests in a declarative style, which is often more readable and easier to understand.

Pest allows testing all parts of our application. We can test if our routes behave correctly, if the data is stored correctly in the database, or if the correct emails are sent.

To test our newsletter system, we will create two tests:


A test for verifying the newsletter user.
A test for subscribing new users using the Livewire component.


In these tests, we verify whether users can subscribe to the newsletter and verify whether verification emails are being sent and whether flash messages are displayed correctly.

Testing the Livewire component - NewSubscriberFormTest.php:

&lt;?php

use App\Enums\Newsletter\NewsletterLanguage;
use App\Http\Livewire\Guest\Newsletter\NewSubscriberForm;
use App\Mail\App\Guest\Newsletter\NewsletterVerificationMail;
use App\Models\Newsletter\NewsletterUser;
use Illuminate\Support\Facades\Mail;
use Livewire\Livewire;

it('subscribes a new user to the newsletter and sends a verification email', function () {
    Mail::fake();

    Livewire::test(NewSubscriberForm::class)
        ->set('email', 'test@example.com')
        ->set('language', NewsletterLanguage::ENGLISH->value)
        ->call('subscribe')
        ->assertDispatchedBrowserEvent('alert');

    expect(NewsletterUser::where('email', 'test@example.com')->first())
        ->email->toEqual('test@example.com')
        ->language->toEqual(NewsletterLanguage::ENGLISH)
        ->is_verified->toBeFalse();

    Mail::assertSent(NewsletterVerificationMail::class, function ($mail) {
        return $mail->newsletterUser->email === 'test@example.com' && 
            $mail->newsletterUser->language === NewsletterLanguage::ENGLISH;
    });
});

it('validates the new user subscription input data', function () {
    Livewire::test(NewSubscriberForm::class)
        ->set('email', 'invalid-email')
        ->set('language', 'invalid-language')
        ->call('subscribe')
        ->assertHasErrors(['email', 'language']);
});

Testing the controller - NewsletterUserControllerTest.php:

&lt;?php

use App\Models\Newsletter\NewsletterUser;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;

it('verifies a newsletter user successfully and redirects to the homepage with a success flash message', function () {
    $newsletterUser = NewsletterUser::factory()->create();

    $response = $this->get(URL::signedRoute('newsletter.verify-user', [
        'language' => $newsletterUser->language,
        'token' => $newsletterUser->verification_token
    ]));

    $response->assertStatus(302);
    $response->assertRedirect(route('homepage', ['language' => $newsletterUser->language]));
    $response->assertSessionHas('flashType', 'success');
    $response->assertSessionHas('flashMessage', __('template.newsletter-successfuly-verified'));

    $newsletterUser->refresh();
    expect($newsletterUser->is_verified)->toBeTrue();
});

it('fails to verify a newsletter user for an invalid token and redirects to the homepage with an error flash message', function () {
    $response = $this->get(URL::signedRoute('newsletter.verify-user', [
        'language' => Config::get('translatable.fallback_locale'),
        'token' => 'invalidtoken'
    ]));

    $response->assertStatus(302);
    $response->assertRedirect(route('homepage', ['language' => Config::get('translatable.fallback_locale')]));
    $response->assertSessionHas('flashType', 'error');
    $response->assertSessionHas('flashMessage', __('template.newsletter-invalid-token'));

    expect(NewsletterUser::where('is_verified', true)->count())->toBe(0);
});

Pest provides us with a range of methods for asserting such as assertStatus, assertRedirect or for example assertSessionHas. To verify the status in the database, we can use the assertDatabaseHas method.



When writing tests, it is important to make sure that the tests cover all possible scenarios and that they are independent of each other. This means that each test should have its own isolated state and should not affect the results of other tests.

Working with Actions

Actions in Laravel help us keep our code organized and ensure that each operation is clearly defined. In our newsletter subscription system, we created two key actions - CreateNewsletterUserAction and VerifyNewsletterUserAction, which we did not discuss in the article.

CreateNewsletterUserAction is responsible for creating a new user in our newsletter database. This is where the email and language chosen by the user for receiving the news are recorded.

&lt;?php

namespace App\Actions\Guest\Newsletter;

use App\Models\Newsletter\NewsletterUser;

class CreateNewsletterUserAction
{
    public function execute(array $validatedData): NewsletterUser
    {
        return NewsletterUser::create($validatedData);
    }
}

Then, VerifyNewsletterUserAction verifies the user based on the token received in the verification email. This action also sets the is_verified flag to true upon successful verification.

&lt;?php

namespace App\Actions\Guest\Newsletter;

use App\Models\Newsletter\NewsletterUser;

class VerifyNewsletterUserAction
{
    public function execute(NewsletterUser $newsletterUser): NewsletterUser
    {
        $newsletterUser->update([
            'is_verified' => true,
            'verification_token' => null
        ]);

        return $newsletterUser;
    }
}

These two actions demonstrate how we can effectively organize our operations in Laravel. They make it easier for us to scale our newsletter system in the future.

Using Enum for Language Settings

The NewsletterLanguage enumerator provides us with an elegant and safe way to manipulate language codes in our application. By using Enum, we are sure that we will only work with permitted values - in our case, en for English and cs for Czech.

Using Enum also increases the readability of the code and simplifies maintenance, as all possible values are centralized in one place.

&lt;?php

namespace App\Enums\Newsletter;

use Illuminate\Support\Collection;

enum NewsletterLanguage: string
{
    case ENGLISH = 'en';
    case CZECH = 'cs';

    public static function all(): Collection
    {
        return collect(NewsletterLanguage::cases())->map(
            fn(NewsletterLanguage $code) => $code->details()
        );
    }

    public function details(): array
    {
        return match($this) 
        {
            self::ENGLISH => [
                'name'  => 'English',
                'value' => 'en',
            ],

            self::CZECH => [
                'name'  => 'Czech',
                'value' => 'cs',
            ],
        };
    }
}

The all and details methods then allow us to easily obtain all available languages and their details, which is useful for example when filling in a language selection field in the form.

Homework


Use of enumerator in Livewire component
In the template at the Livewire component, I used iteration over an array stated in the configuration file, specifically in app.php - config('app.locales'). However, in production, it would be ideal to use enum.
Hint: Why do we have the all() method in the enumerator? Could it be used?
Handling of validation messages
The Livewire component is not completely translated. Laravel can output messages in English for error messages, but not in Czech.
Hint: Livewire has a nicely described documentation and with the use of Laravel documentation, this task should be easily solvable.
Creating a seeder
If you want to have a database filled with randomly generated data and you do not want to rely only on tests, you will definitely use a seeder. This also makes it easier for other developers to understand your application without the need to create data manually.
Hint: Since we have a factory for creating model instances, including an example of use in the test, nothing should cause you problems.
Send mail in the queue
So that the user does not wait until the function is executed (an email is sent), you can use processing via so-called queues for the email.
Hint: Laravel again has everything nicely summarized in the documentation. Personally, I recommend "implementing" the use of a queue in the file for email logic (i.e., the only class that is not used in our demonstration, yet the file contains it - it is even added if you generate the file via the artisan command).


Conclusion

Creating a newsletter subscription system in Laravel may seem like a complex task. This article should show you that it is not as complicated as it might seem at first glance. Thanks to this guide, you had the opportunity to familiarize yourself with the whole process from basic preparation to the implementation of individual parts and testing.

Laravel is a powerful and flexible framework that allows you to create different types of web applications. Using Livewire, we can easily create dynamic components and thanks to Pest, we can effectively test our application and make sure everything works correctly.

It is also important to remember internationalization and prepare our application for multilingual users. Laravel provides great tools for working with translations and localization.

I hope this guide has helped you understand how to create a newsletter subscription system in Laravel and that it has inspired you for further projects. Remember, practical experience is the most important thing, so don't hesitate and start your own project!]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/47/47139203-32b9-48cc-bdb8-21e65429cf98/conversions/laravel-newsletter-system-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Factories for Astrotomic Laravel Translatable]]></title>
                <link>https://www.pavelzanek.com/en/blog/factory-astrotomic-laravel-translatable</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/factory-astrotomic-laravel-translatable</guid>
                <pubDate>Sun, 18 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Learn how to create factories for Astrotomic Laravel Translatable. The guide covers setup, creating factories, and testing them for multilingual applications.]]></description>
                
                                    <content:encoded><![CDATA[What is a factory in Laravel and why use it
A factory in Laravel is a tool that simplifies the generation of a large amount of test data for our database tables. Factories are essential for automated testing, where we need to create various scenarios for our tests.
Using factories in Laravel brings several advantages. One of them is efficiency - instead of manually creating individual records in the database, we can use a factory that generates the required amount of data for us. Another advantage is flexibility. Factories allow us to define different states of our models, which allows us to easily create different database scenarios for our tests.
In the following sections, we will look at how to create a basic factory in Laravel and how to modify it for use with the Astrotomic/laravel-translatable package for translations.

Basics of creating a factory in Laravel
Creating a factory in Laravel is a simple process that allows you to quickly generate test data for your database tables. Here is a guide on how to create a basic factory in Laravel.
The first step is to create a factory using the Artisan command. Open the terminal and enter the following command:
php artisan make:factory ExampleModelFactory --model=ExampleModel
This command creates a new factory named ExampleModelFactory for the ExampleModel model. Laravel automatically creates a factory file in the database/factories directory.
Open the newly created factory file and you will see the definition() method. This method is where you define how each attribute of your model should be generated.
...
public function definition()
{
    return [
        'attribut_name' => $this->faker->word,
        // other attributes...
    ];
}
...
In the definition() method, we use the so-called Faker library, which allows us to generate various types of random data, such as words, sentences, numbers, and other data.
Now that you have created a factory, you can use it to create data for your tests. You can do this, for example, as follows:
$user = UserFactory::new()->create();
In this way, you create a new record in the database with data generated by your factory. Factories in Laravel are a powerful tool that allows you to easily and efficiently generate test data for your applications.

How to use the Astrotomic/laravel-translatable package for translations
The Astrotomic/laravel-translatable package is a tool that allows for easy translations of your models in Laravel. This package is ideal for projects that require multilingual support and allows you to store translations of your models directly in the database.
To be able to use the package, we must first install it. This can be done using the following command:
composer require astrotomic/laravel-translatable
After installing the package, we need to use the Translatable trait in our model that we want to translate. The trait adds methods that allow us to easily work with translations.
...
use Astrotomic\Translatable\Translatable;

class Post extends Model
{
    use Translatable;

    public $translatedAttributes = ['title', 'body'];

    ...
}
In this example, we used the Translatable trait in the Post model and we define that the title and body attributes will be translated. In addition to the trait, we can also add a contract:
...
use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Astrotomic\Translatable\Translatable;

class Post extends Model implements TranslatableContract
{
    use Translatable;

    public $translatedAttributes = ['title', 'body'];

    ...
}
The Astrotomic/laravel-translatable package then allows us to easily access translations and work with them. For example:
$post = Post::first();
echo $post->translate('en')->title; // this will print the English title of the post
The Astrotomic/laravel-translatable package is a powerful tool for working with translations in Laravel. In the next section, we will look at how we can use it when creating factories.

Creating a factory for models with the Astrotomic/laravel-translatable package
Now that we have a basic understanding of how the Astrotomic/laravel-translatable package works, we can look at how to create a factory for models that use this package.
Let's imagine that we have a Post model that uses the Astrotomic/laravel-translatable package for translating the title and body attributes. How would we create a factory for this model?
The first step is the same as we showed in the previous section - we create a factory using the Artisan command:
php artisan make:factory PostFactory --model=Post
Then we open the factory file and modify the definition() method to generate translations for our attributes. We can do this, for example, as follows:
...
public function definition()
{
    $locales = ['en', 'cs'];
    $translations = collect($locales)->mapWithKeys(function($locale) {
        return [
            $locale => [
                'title' => $this->faker->words(3, true),
                'body' => $this->faker->realText(500),
                ...
            ]
        ];
    })->toArray();

    return array_merge($translations, [
        'type' => PostType::POST,  // non-translatable attribute
    ]);
}
...
In this example, we generate translations for English (en) and Czech (cs) using the Faker library. We can add as many languages as we need.
Now that we have created a factory, we can use it to create data for our tests in the same way as we showed in the previous section. In this way, we can easily create factories for models that use the Astrotomic/laravel-translatable package for translations.

Conclusion
In this article, we have thoroughly familiarized ourselves with the process of creating a factory for models in Laravel using the Astrotomic/laravel-translatable package for translations. We went through the basics of creating a factory, got acquainted with the Astrotomic/laravel-translatable package, and finally showed how to create a factory for models that use this package.
We hope that this guide has helped you understand how to effectively use factories in Laravel and how to combine them with the translation package. Laravel is a powerful framework that offers many tools and features that make web application development easier. Factories and the translation package are just a small part of what Laravel offers.
If you want to deepen your knowledge of Laravel and its features, I recommend looking at other resources and tutorials/guides that are available online. Also, don't be afraid to experiment and try new things - that's the best way to learn and improve your skills. I wish you a lot of success and joy in developing with the Laravel framework!]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/7f/7f22f39b-f249-4529-9fcc-3d2377974ac4/conversions/factories-astrotomic-laravel-translatable-full.png" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Title tag – a complete guide for SEO]]></title>
                <link>https://www.pavelzanek.com/en/blog/title</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/title</guid>
                <pubDate>Wed, 14 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[A guide to the title tag for SEO: What is a title tag, how to write it correctly, what impact it has on SEO and how to optimize it for search engines.]]></description>
                
                                    <content:encoded><![CDATA[The page title, also known as the title tag, is a key element of search engine optimization (SEO). It's the first thing users see when they come across your page in search results, and it can have a big impact on whether or not they click on your link. In this article, you'll learn what a title is, how search engines use it, best practices for creating one, and how you can use it to improve your SEO strategy. We'll also look at tools that can help you control and improve your titles. Whether you're an SEO beginner or a seasoned expert, this guide will provide you with valuable information and tips on how to create effective titles for your website.
What's the title?
The title is a key element of any website. It is a short text that describes the content of the page. The title appears in several important places. It is most visible in the browser header or browser tab when the page is open. The title is also the main element in search results, where it appears as a clickable link to your page. In addition, the title may appear on external sites such as social networks when the page is shared.
The title is extremely important for SEO. It's one of the first places search engines (like Google) look for keywords when trying to understand what your page is about. A well-written title can greatly improve your page's visibility in search results. On the other hand, if the title is poorly written or does not contain relevant keywords, it can hurt your page in search results.
Title Example:
&lt;title&gt;Useful links - Laravel framework - PavelZanek.com&lt;/title&gt;
Rules for creating a caption
I have prepared some rules for subtitling that you can use. Let's take a look at them.

The uniqueness of the title
Every page on your website should have a unique title. Duplicate titles can lead to confusion for search engines and users. You can check the uniqueness of your titles using tools like Screaming Frog.
Title length
The ideal title length is between 50-60 characters. If the title is too long, search engines may truncate it in the SERPs (search results). If, on the other hand, it's too short, it may mean you're not using enough space for keywords and for persuading users to click on your link.
Use of keywords
Keywords should be part of your title. You should try to place the main keyword as close to the beginning of the title as possible. This makes it easier for search engines and users to understand what the page is about.
Exact description of the content
The title should accurately and concisely describe the content of the page. Users should be able to quickly understand what to expect on the page after reading the title.
Focus on users
When creating a title, think about your users. The title should be attractive and compelling so that users want to click on your link.
Brand use (brandbuilding)
If your brand is well known, it can be useful to include it in the title. Usually the brand is placed at the end of the title.
Technical aspects
The title should be properly implemented in the HTML code of your page using the &lt;title&gt; tag. You should also avoid using unusual characters that could cause coding problems.
Testing and optimization
You should regularly monitor the performance of your titles and perform A/B tests where appropriate to see what formatting or what phrases lead to higher clickability and better positions in search results.
Rules for specific page types
There are also specific rules for different types of sites. For example, for product pages, the title should include the product name and its main features. For blog posts, the title should pique the interest and curiosity of readers.
Avoiding keyword spam
Excessive use of keywords in the title can lead to a search engine penalty. Instead, try to create a natural-sounding title that still contains your keyword.
Use of emotions and action words
Emotional and action words can increase the clickability of your title. For example, words like "best", "fastest" or "latest" can attract users' attention.
Using numbers and listsNumbers and lists can also increase the clickability of your title. For example, "Top 10 tips for..." or "Top 5..."
Use of local SEO
If your business is focused on a specific geographic area, it can be helpful to include the name of the city or region in the title.
Use of current events and trends
If relevant to your content, you can include a reference to current events or trends in your title.
Avoiding misleading titles
Misleading titles can lead to high bounce rates and can damage your reputation with search engines and users. Make sure your title accurately matches the content of the page.
Use of structured data
Structured data can help search engines better understand the content of your page and can lead to better display of your title in search results.
Use of social signals
Social signals, such as social sharing, can also influence how search engines rank and display your title. Make sure your title is attractive and shareable.
Avoiding technical errors
Technical errors, such as incorrect encoding of special characters, can cause your title to appear incorrectly in search results. Make sure your title is technically correct.
Use of consistency
Consistency in the format and style of your titles can help users better recognize and remember your brand.
Use of timeliness
Updating titles based on current trends, seasonal changes or new information can help keep your site relevant and attractive to users.
Use upper and lower case letters
Instead of using only uppercase or lowercase, try using a combination of both. Capital letters can be used to emphasize key parts of the title and help keep the reader's attention.
Do not reuse special characters
Repeated use of special characters, such as dashes (-), vertical bars (|) or commas (,), in titles can be distracting and less professional. Try to use these characters sparingly and always with an eye to the readability and clarity of the title.


Creating effective titles is a key part of SEO. A well-crafted title can increase your website's visibility in search results, increase clickability and attract more visitors to your site. Always make sure your title is unique, relevant, attractive and technically correct.
Correct title length
When creating titles, one of the key aspects is their length. The optimal length of a title is a subject of much debate among SEO experts. It is generally recommended that the length of the title should not exceed 60-70 characters. This length is ideal for displaying the full title in Google search results. If the title is longer, Google may shorten it, which can lead to important information being lost.
Characters vs pixels
It's important to note that Google doesn't limit titles by character count, but by width in pixels. This means that the length of the title in characters can vary depending on what characters are used. For example, wide characters such as 'W' or 'M' take up more space than narrower characters such as 'i' or 't'. Therefore, it is important to consider not only the number of characters but also the width in pixels when creating a title. However, there are tools that can help you check that the length of your title is within the recommended limits.
Title length on desktop and mobile
When creating titles, it's important to consider that they can be displayed on different devices - desktop and mobile. Depending on the device, the length of the title can vary.

Desktop
On desktop devices, there is generally more space to display the title. Google usually displays the first 50-60 characters of the title. If the title is longer, it may be truncated. It is therefore important that the most important information is placed at the beginning of the title.
Mobile devices
On mobile devices, the space for displaying the title is more limited. Google usually displays the first 40-60 characters here. Again, if the title is longer, it can be shortened. This makes it even more important to place key information at the beginning of the title.

How search engines work with titles
How search engines read titles
Search engines like Google use sophisticated algorithms to read and interpret titles. These algorithms are designed to recognize keywords and phrases in the title that are relevant to the content of the page. When a user enters a query into a search engine, the algorithm finds the pages with titles that best match the user's query. But this is just one of many factors that search engines use.
How search engines rank titles
Search engines also rank titles based on several factors. One of them is the uniqueness of the title. Sites with unique and original titles are often ranked higher than sites with duplicate titles. Another factor is the relevance of the title to the content of the page. Pages whose titles match the content of the page exactly are often ranked higher than pages with mismatched titles.
How search engines display titles
Search engines display titles in their search results as the main link to the page. The title is often the first thing users see when their page appears in search results, and can have a big impact on whether or not a user clicks on the link. Some search engines, such as Google, may also adjust the display of the title to better match the user's query.
How search engines use titles to rank search results
Search engines use titles as one of many factors in ranking pages in search results. Pages with titles that are well written and contain relevant keywords often rank higher than pages with poorly written or irrelevant titles. Search engines also take into account how often a keyword is used in a title and may penalise sites that overcrowd their titles with keywords.

How search engines deal with title changes

How search engines detect changes in titles
Search engines like Google regularly crawl websites to see if there have been changes. This process is called crawling. During this process, search engines detect if any changes have been made to the page titles. If a change is detected, the search engine updates its index and may reevaluate the page's position in the search results.
How search engines react to changes in titles
If a search engine detects a change in a page's title, it can affect how the page is ranked and displayed in search results. If the new title is more relevant and contains keywords that are important to the content of the page, this can lead to a higher page ranking. On the other hand, if the new title is less relevant or does not contain important keywords, it may lead to a lower page ranking.
How long it takes search engines to react to changes in titles
The time it takes search engines to respond to changes in titles can vary. Some changes may be detected and acted upon within a few days, while others may take weeks or even months. This is determined by many factors, including the frequency of search engine crawling, the size and popularity of the website, and the nature of the title changes.

Impact of title changes on SEO

Impact of title changes on search engine rankings
As mentioned earlier, changing your title can have a significant impact on your page's search engine ranking. If the new title is more relevant and contains keywords that are important to the content of the page, it can lead to higher page rankings.
Impact of title changes on click-through rate (CTR)
Changing your title can also affect your page's click-through rate (CTR). The title is one of the first elements users see when your page appears in search results, and can have a big impact on whether or not a user clicks on a link. If the new title is more attractive or more accurately describes the content of the page, it can lead to a higher click-through rate.
Impact of title changes on page traffic
Changing your title can also affect your page traffic. If the new title is more relevant and appealing to users, it can lead to more traffic to the page.
Impact of title changes on conversions
Changing your title can also affect the conversion rate of your page. If the new title is more compelling and motivates users to take action, it can lead to higher conversion rates. On the other hand, if the new title is less compelling or less motivating, it can lead to lower conversion rates.

How to avoid the negative effects of title changes

Through keyword research
Before making any changes to your titles, it's important to conduct thorough keyword research. Keywords are the cornerstone of SEO and can have a big impact on how your site is ranked in search engines. When choosing keywords, consider how relevant they are to your page content, how often they are searched for, and how competitive the competition is for those keywords.
Testing and monitoring results
If you make changes to your titles, it's important to track those changes and measure the results. This will allow you to see if your changes have led to positive or negative results. You can track metrics such as search rank, click-through rate (CTR) and page traffic. If you find that your changes have led to negative results, you can decide to go back to your original title or try something else.
Consideration of user experience
When changing titles, it is also important to consider the user experience. The title is one of the first elements users see when they visit your site and can have a big impact on their impression of your site. Make sure your title is accurate, descriptive and appealing to users.
Use of professional SEO tools
There are various SEO tools that can help you optimize your titles and track the results of your changes. These tools can provide valuable information and insights to help you make informed decisions about how best to adjust your titles.

Tools for checking and improving titles
Check out a few selected tools to help you optimize your titles.

Meta Title Test
This tool allows you to check if your web title meets basic SEO requirements. It shows your page title in search results, at the top of the user's browser and also when your page is saved in the favorites list. A concise, descriptive title that accurately reflects the topic of your page is important for ranking well in search engines.
Meta Length Checker
This tool allows you to check the length of your title. Title length is an important factor in SEO, as titles that are too long can be truncated in search results.
Google SERP Snippet Optimization Tool
This tool allows you to optimize how your title appears in Google search results (SERPs). You can experiment with different titles to see how they appear in search results.
Screaming Frog
Screaming Frog is an SEO optimization tool that allows you to optimize titles, meta descriptions and other aspects of your website. This tool can help you improve your site's search engine rankings.


When using these tools, it's important to remember that SEO best practices can change over time, so it's important to always stay on top of the latest trends and recommendations.
12 tips for improving your title

Use keywords
Keywords are the foundation of SEO. Make sure your keywords are in the title and that they are relevant to the content of the page.
Be concise and clear
The title should be concise and clear. It should quickly and effectively reflect what the page is about.
Use numbersNumbers in a title can be very effective. For example, "10 Tips for Improving SEO" is more appealing than "Tips for Improving SEO".
Use action verbs
Action verbs can motivate readers to click. For example, "Find out how to improve SEO" is a better use than "Improve SEO".
Create curiosity
Using mystery or curiosity in a title can motivate readers to want to know more.
Use emotional words
Emotional words can make readers more engaged and motivate them to take action.
Make sure the title matches the content of the page
Don't promise anything in the title that doesn't match the content of the page. This could lead to high bounce rates and could hurt your SEO.
Use unique titles for each page
Duplicate titles can be confusing to search engines and can hurt your SEO.
Optimize for mobile devices
Make sure your title looks good on mobile devices where fewer characters may be displayed.
Test and edit
SEO is an ongoing process. Test different titles and see which ones work best.
Don't forget the brand (brandbuilding)
Brands can be useful for increasing brand visibility and improving SEO.
Use tools to check titles
There are tools that can help you optimise and improve your titles.

Managing titles in content management systems
Content management systems, also known as Content Management Systems (CMS), are tools that make it easier to manage and publish content on a website. These systems allow users to create, edit and publish content without the need for advanced technical skills.
In the context of SEO and title management, content management systems are key. Most modern CMSs allow users to easily add and edit page titles, which is essential for search engine optimization. Some systems even provide tools to track title length and display warnings if a title is too long or short.
When choosing a content management system, it is important to consider how well the system supports SEO. Some features that a quality content management system should have include the ability to easily edit titles, meta descriptions and other SEO relevant elements, support for structured data, and the ability to generate and edit sitemaps and robots.txt files.
Choosing the right content management system can make all the difference in the success of your SEO. That's why it's important to carefully consider all your options and choose the system that best suits your needs.
Wordpress tip
One tip for managing titles in Wordpress is to use SEO plugins such as RankMath or Yoast SEO. These plugins provide advanced tools for managing titles and other SEO elements. For example, they allow you to set the format of titles for different types of pages, automatically generate titles based on defined templates, or analyze titles and provide feedback to optimize them.

Titles and social networks
Social networks have become an integral part of our everyday lives and play a key role in digital marketing. When we share the URL of our website on these platforms, the page title becomes the main title that users see. Having an attractive and compelling title can significantly increase the click-through rate to your website.
OpenGraph, TwitterCards and Schema.org: the three pillars of social networking
OpenGraph, TwitterCards and Schema.org are brands that allow websites to interact with social networks and provide them with specific information about the content of the page. If your page lacks these tags, social networks will use the page title as a title when sharing the URL. However, I recommend including these 3 tags on your site - only as a last resort can you rely on the title. Additionally, you have the option to have different titles on both search engines and social networks - which is sometimes useful, after all, the behaviour of your target audience on social networks is different than on search engines.
Conclusion and next steps
The importance of the title for SEO is immense. It's one of the first things users and search engines see when they come across your website. A well-written title can increase your traffic, improve your ranking in the SERPs, and increase the overall visibility of your website.

Use tools to check your titles: there are various tools that can help you check and improve your titles. Use them to optimize your titles.
Experiment and test: SEO is an ongoing process. Don't be afraid to experiment with different formats and words in your titles and see what works best for your audience and your goals.
Don't forget about other aspects of SEO: While titles are important, don't forget about other aspects of SEO such as meta description, URL structure, internal and external links, page content and more.
Educate yourself: SEO is constantly changing and evolving. Stay up-to-date on the latest trends and best practices in SEO so you can continually optimize and improve your website.

Remember that success in SEO is not about one-off efforts, but about continuously improving and adapting to the changing digital landscape. With these tips and tools, you're now ready to create effective titles that attract visitors and improve your SEO.
FAQ / Frequently Asked Questions
What is the title of the page?
The page header is a short text that describes the content of the page. It is one of the first things users and search engines see when they come across your website.
How to check titles?
You can display titles in your browser's bookmark title or by using SEO tools that allow you to view and analyze website meta data (although title is not part of the meta data). Last but not least, you can quickly double-check titles using the site operator.
How long should the page title be?

For Google
Google generally recommends that page titles be between 50-60 characters. If the title is longer, it may be truncated in search results.
For Bing
Bing has not published specific recommendations for title length, but it is generally recommended to stick to the 50-60 character standard that is common for most search engines.
For Yahoo
Like Bing, Yahoo has not published specific recommendations for title length. In general, it is recommended to stick to the standard 50-60 characters.
For other search engines
For other search engines, it is recommended to stick to the general 50-60 character rule. It is important to remember that in addition to length, the title should also be relevant and descriptive.
]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/4a/4a8f8026-0cae-489e-8f72-4b9e61b4bb02/conversions/title-tag-full.png" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Structured data – a complete guide for SEO]]></title>
                <link>https://www.pavelzanek.com/en/blog/structured-data</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/structured-data</guid>
                <pubDate>Wed, 07 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[A guide to structured data for SEO: What is structured data, how to implement it on your website, and how it can improve your search engine results.]]></description>
                
                                    <content:encoded><![CDATA[Introduction to structured data
Structured data is a key element for an effective SEO strategy. They help search engines like Google better understand the content on your site and provide them with accurate information that can improve your visibility in search results.
Structured data is basically code that is added to your web page that gives search engines more information about the content of the page. For example, this could be information about the author of an article, a product rating, or the date and location of an event.
What is structured data?
Structured data is a specific format of information that is easily understood by machines. They are essentially pieces of code that are added to a web page that provide search engines like Google or List with detailed information about the content of the page.
Structured data formats: JSON-LD, Microdata, RDFa
There are different formats you can use to add structured data to your website. The most commonly used formats are JSON-LD, Microdata and RDFa.

JSON-LD is a format that is recommended by Google. It's the easiest format for adding structured data to a web page, and it's also the most flexible.
Microdata is another format you can use. It is a bit more complex than JSON-LD, but it is also very flexible.
RDFa is a format that is often used to add structured data to web pages that are built on HTML5.

How structured data affects SEO
Structured data plays a key role in SEO because it helps search engines better understand the content on your website. When search engines better understand your website content, they can more accurately index and rank your site, which can lead to better rankings in search results.
How structured data improves visibility in search results
Structured data also allows search engines to display so-called advanced search results, which can increase the click-through rate to your website. Enhanced search results can include elements such as star ratings, images and other information that can attract users' attention.
Examples of using structured data for SEO
There are many ways you can use structured data to improve SEO. For example, if you have a recipe article on your site, you can use structured data to provide specific information about the recipe, such as preparation time, number of servings, recipe rating, and more. This structured data can help search engines better understand the content of your article and display it in search results for relevant queries.

How to implement structured data on the web
See an example/example of deploying structured data using JSON-LD format:

Choose the type of structured data you want to implement: there are many different types of structured data you can implement on your site, including data for articles, products, reviews, events, and more. The type of structured data you choose should match the content of your site.
Create a JSON-LD script for your structured data: JSON-LD is the format recommended by Google for implementing structured data. This script should contain all the information you want to provide to search engines about your content.
Insert the JSON-LD script into the HTML code of your website: This script should be embedded in the header (&lt;head&gt;) of your HTML code.
Test your structured data: once you've implemented structured data, you should use tools like Google's Structured Data Testing Tool to verify that your structured data is properly implemented and that search engines can read it correctly.

Tools for implementing structured data
There are a number of tools that can make it easier to implement structured data on your site. Some of these tools include:

Google's Structured Data Markup Helper: This tool helps you create a JSON-LD script for your structured data.
Schema.org: This is the main source for different types of structured data you can implement on your website.
WordPress plugins: if you use WordPress to manage your site, there are plugins that can automate the process of implementing structured data - for example RankMath.

Types of structured data
Structured data is a key element of modern SEO and, as mentioned, its proper use can significantly improve your website's visibility in search results. There are several different types of structured data that can be used for different purposes.



Type
Description






Schema.org
Schema.org is a joint project of Google, Microsoft, Yahoo and Yandex that provides a shared collection of schemas for structured data. These schemas cover a wide range of content types, including articles, books, movies, music recordings, reviews, products, and many more. Schema.org is Google's recommended format for structured data.


Open Graph
Open Graph is a type of structured data that was originally developed by Facebook. It is designed to enable better integration of websites with social media, by providing metadata that can be used to create rich "snippets" for sharing on social media.


JSON-LD
JSON-LD (JavaScript Object Notation for Linked Data) is a popular format for structured data that is easily readable by humans and machines. JSON-LD is Google's recommended format for structured data and is widely supported by many other search engines and platforms.


Microdata
Microdata is another format for structured data that is integrated directly into the HTML code of a web page. While not as flexible as JSON-LD, it is still widely supported and can be useful for simpler structured data implementations.



Specific types of structured data
Article / NewsArticle / BlogPosting
This schema type is designed to describe articles and blog posts. Article is a more general schema type that can be used for any text content structured as an article. NewsArticle is a specific schema type often used by publishers for news articles. BlogPosting is a schema type often used by organizations with websites containing blog posts. This schema type can include information such as the author, publication date, image, and much more.
Event
The Event schema type describes any planned activity, including its location and start and end times. It can be conferences, concerts, sports events, exhibitions, and much more. This schema type can include information such as the event name, description, date and time, location, organizer, and other relevant information.
Job Posting
The Job Posting schema type describes a specific job offer, including information such as the job title, job description, employment type (full-time, part-time, temporary, etc.), salary, currency, job location, the organization offering the job, and other relevant information.

Local Business
The Local Business schema type describes a physical store or business, including information such as opening hours, location, contact information, business type (restaurant, shop, cafe, etc.), ratings, and more. This schema type is very useful for local SEO and to improve the visibility of the business in local searches.
Organization
The Organization schema type describes any organization, including the website address, social media profiles, contact information, and more. This schema type is often used for organizations that people do not physically visit, such as online stores, non-profit organizations, government organizations, and others.
Person
The Person schema type describes an individual. This schema type can include information such as name, title, job position, contact information, social media profile, education, skills, and more. This schema type is often used in relation to defining the Author schema type for an article, but can also be used to describe any person, including public figures, employees, team members, and others.
Product
The Product schema type describes any product or service offered by an organization. This schema type can include information such as product name, description, brand, price, reviews, offers, and more. This schema type is very useful for e-commerce websites and to improve the visibility of products in organic search results.

Recipe
The Recipe schema type describes any recipe, including ingredients, preparation steps, preparation and cooking time, number of servings, nutritional information, images, and more. This schema type is very popular on recipe websites and can help improve the visibility of recipes in organic search results.
Review
The Review schema type describes a review of either a specific item or a collection of items, or a critical review. This schema type can include information such as the review author, rating, review publication date, the item being reviewed, and more. This schema type is very useful for websites that contain reviews of products, services, places, events, and others.
Structured data examples
For a better understanding of structured data, let's look at several examples of its deployment.
Example for the Organization type
This sample JSON-LD code represents structured data for an organization named "PavelZanek.cz". The code defines several key pieces of information about the organization, including its name, URL, contact information, and founder (heh).
&lt;script type="application/ld+json"&gt;
{
    "@context": "http://schema.org",
    "@type": "Organization",
    "name": "PavelZanek.com",
    "url": "https://www.pavelzanek.com",
    "sameAs": [
        "https://www.facebook.com/pavelzanekcz"
    ],
    "contactPoint": {
        "@type": "ContactPoint",
        "telephone": "+420 608 838 170",
        "contactType": "work phone number",
        "email": "info@pavelzanek.com"
    },
    "founder": {
        "@type": "Person",
        "name": "Pavel Zaněk",
        "gender": "Male",
        "jobTitle": "Developer a SEO consultant",
        "image": "https://www.pavelzanek.com/template/pavelzanek.jpeg",
        "sameAs": [
            "https://pavelzanek.cz/",
            "https://twitter.com/PavelZanek",
            "https://www.linkedin.com/in/pavelzanek/",
            "https://github.com/pavelzanek"
        ]      
    },
    "foundingDate": "2022-14-01"
}
&lt;/script&gt;
In this code, @context is set to "http://schema.org", which means we are using schema.org to define structured data. @type is set to "Organization", which means that this data structure describes an organization.
"name" and "url" define the name and web address of the organization. "sameAs" is a field that contains links to other web pages that represent this organization, in this case the Facebook page.
"contactPoint" is an object that defines an organization's point of contact, including phone number, contact type, and email address.
"founder" is another object that defines the founder of the organization, including his name, gender, job title, picture and links to his profile on various social networks and websites.
Finally, "foundingDate" defines the founding date of the organization.
Example for the Person type
Another sample JSON-LD code represents structured data for a person named "Pavel Zaněk" (Yeah, it's me!). The code defines several key information about me, including his name, job title, picture, gender, nationality, place of birth, website address and more.
&lt;script type="application/ld+json"&gt;
{
    "@context": "http://schema.org",
    "@type": "Person",
    "name": "Pavel Zaněk",
    "jobTitle": "Developer a SEO consultant",
    "image": {
      "@type": "ImageObject",
      "image": "https://www.pavelzanek.com/template/pavelzanek.jpeg",
      "width": "128",
      "height": "128"
    },
    "gender": "Male",
    "nationality": "Czech",
    "birthPlace": "Chrudim",
    "url": "https://www.pavelzanek.com/",
    "sameAs": [
        "https://pavelzanek.cz/",
        "https://twitter.com/PavelZanek",
        "https://www.linkedin.com/in/pavelzanek/",
        "https://github.com/pavelzanek"
    ],
    "worksFor": [
        {
            "@type": "Organization",
            "name": "PavelZanek.cz",
            "sameAs": [
                "https://www.facebook.com/pavelzanekcz"
            ]
        }
    ],
    "email": "info@pavelzanek.com",
    "telephone": "+420 608 838 170",
    "address": {
        "@type": "PostalAddress",
        "streetAddress": "Slovensk&aacute; 518",
        "addressLocality": "Chrudim",
        "postalCode": "537 05",
        "addressCountry": "Česk&aacute; republika"
    }
}
&lt;/script&gt;
In the code above, @context is set to "http://schema.org" which means we are using schema.org to define structured data. @type is set to "Person", which means that this data structure describes a person.
"name", "jobTitle", "gender", "nationality", "birthPlace", "url", "email", "telephone" and "address" define basic information about me. "sameAs" is a field that contains links to other websites that represent me.
"worksFor" is an array that contains objects defining the organizations I work for. Each object in this field has @type set to "Organization", which means it describes the organization, and "name" and "sameAs", which define the name of the organization and links to other web pages that represent that organization.
Example for the Breadcrumb Type
The last sample JSON-LD code represents structured data for breadcrumb navigation (BreadcrumbList). The code defines the structure of the navigation on the web page, including the names and URLs of individual elements.
&lt;script type="application/ld+json"&gt;
{
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [
        {
            "@type": "ListItem",
            "position": 1,
            "name": "Home",
            "item": "https://www.pavelzanek.com/en"
        },
        {
            "@type": "ListItem",
            "position": 2,
            "name": "Contact",
            "item": "https://www.pavelzanek.com/en/contact"
        }
    ]
}
&lt;/script&gt;
In this code, @context is set to "https://schema.org", which again means we are using schema.org to define structured data. @type is now set to "BreadcrumbList", so this data structure describes breadcrumb navigation.
"itemListElement" is an array that contains objects defining individual elements of the granular navigation. Each object in this array has @type set to "ListItem", that is, it describes the item in the list, and "position", "name", and "item", which define the item's position in the list, the item's name, and the item's URL.
Use of structured data
The uses of structured data are wide and varied, and if implemented correctly, they can contribute significantly to the success of your online presence. The following section takes a closer look at some of the most common uses of structured data.
Improving SEO
Structured data is one of the most important tools for search engine optimization (SEO). It helps search engines better understand your website content and provides them with detailed information that can improve your rankings in search results.
Increase visibility
Structured data can increase your website's visibility by allowing search engines to display rich snippets such as star ratings, product prices, images and more. These rich results can increase the clickability (CTR) of your link in search results.
Improving the user experience
Structured data can also improve the user experience by giving users more information directly in search results. For example, if you have an e-commerce store, you can use structured data to display prices and product ratings directly in search results, making it easier for users to make purchasing decisions.
Support for specific content types
Structured data also supports specific content types such as recipes, reviews, events and more. If you provide this type of content on your website, you can use structured data to improve its presentation in search results.

Deployment check
If you have deployed structured data on your website, then it is always a good idea to check it - to see if there has been any major error in the implementation or if the search engine will give us any further recommendations.
We can do a deployment check in 2 ways. Either you use Google's tool - Structured Data Test, or you use Google Search Console.
So let's look at the first way of checking. Just go to the "Structured Data Test" tool and enter the URL where you want to check the deployment. Alternatively, you can then paste the source code of the page (useful if the page is not yet publicly available).

After analyzing it, the tool will show you what structured data is implemented on a particular URL (or in the code) and whether it contains errors.
Now let's look at the second point and that is testing the structured data using the Google Search Console tool. GSC can show us how the structured data is implemented, whether it contains errors and we can see the progress of the deployment over time. Again, the tool will show you any errors or recommendations that you can fix. The only difference between GSC and the "Structured Data Test" tool is that the Structured Data Test will only check one URL that you paste into the tool (or then the copied source code). GSC gives you an overview of all the pages where structured data is deployed and Googlebot has noticed them.

Best practices for structured data and SEO
Structured data has become a key element of SEO and its proper use can contribute significantly to your website's visibility in search results. In this final section, we'll look at some of the best practices for structured data and SEO.

Use the right format: Google recommends using JSON-LD for structured data. It's simpler and cleaner than other formats like microdata or RDFa.
Tag relevant content: not all information on your website needs structured data. Focus on key elements such as product names, reviews, prices, etc.
Test and Verify: Google offers a structured data testing tool that you can use to validate your data (or using the URL Inspection tool within Google Search Console).
Update regularly: structured data should be updated to reflect current information.
Use multiple types of structured data: there are many different types of structured data you can use on your website. For example, you can use structured data for reviews, recipes, products, events, and much more.

Conclusion
Structured data is a powerful tool that can significantly improve your website's visibility in search results. Although they can be technically challenging to implement, the benefits they bring are huge. With the right tools and practices, you can effectively use structured data to maximize your SEO efforts.
TIP: You can find more information about structured data in my earlier post (in Czech).]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/c3/c3a21d75-aaa9-4219-ac59-31cc41385a77/conversions/structured-data-full.png" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Complete Guide to ChatGPT 2023]]></title>
                <link>https://www.pavelzanek.com/en/blog/chatgpt</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/chatgpt</guid>
                <pubDate>Tue, 06 Jun 2023 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Explore the world of ChatGPT in a step-by-step guide. You will learn what ChatGPT is, how to use it, what its capabilities and limitations are, and what the plans are for its future.]]></description>
                
                                    <content:encoded><![CDATA[Introduction to the world of ChatGPT
Welcome to the amazing world of ChatGPT, an advanced artificial intelligence technology. This technology brings new possibilities in the field of text communication and opens the door to endless possibilities of interaction. ChatGPT, an AI chatbot created by OpenAI in November 2021, is fast becoming a global phenomenon. ChatGPT has capabilities ranging from answering simple questions to writing entire essays and programs.

What is ChatGPT?
ChatGPT is a conversational AI model based on the GPT-3 model and now also on the newer GPT-4 model. These models are capable of generating human texts, answering questions and even writing articles.
Why is ChatGPT important?
ChatGPT represents a significant step forward in the field of artificial intelligence. Its ability to generate persuasive and meaningful text opens up new possibilities in many areas, including customer support, web content, teaching and many more.
What will you learn in this article?
In this article you will learn how to use ChatGPT. I'll walk you through the basics of using this technology, including how to set up ChatGPT, how to interact with it, and how to use its capabilities in your daily life and work.
What is ChatGPT?
ChatGPT is an advanced conversational artificial intelligence model developed by OpenAI. This model is based on GPT (Generative Pretrained Transformer) technology, which is able to generate coherent and meaningful texts based on previous inputs.
The technology behind ChatGPT
As mentioned, ChatGPT uses the GPT-3 and GPT-4 models. GPT-3 is a 175 billion parameter language model created by OpenAI. This model is capable of generating surprisingly human-like text and is used in many applications, including chatbots, automatic article writing, etc.
The GPT-4 is an even more advanced model, introduced in 2023. This model has even more parameters and is capable of generating even more accurate and relevant texts. In addition, the GPT-4 is also able to process images as input, which opens up new possibilities for its use. The GPT-4 model is only available to ChatGPT Plus plan holders (i.e. the paid version of ChatGPT).
It is important to note that although ChatGPT is a very advanced tool, it is not capable of generating images. Its main strength is text generation. However, ChatGPT can be used to create prompts to generate images. These prompts can then be copied and pasted into other tools that are capable of generating images based on text descriptions. In this way, ChatGPT can indirectly contribute to the creation of visual content.
How does ChatGPT work?
ChatGPT uses a large database of pre-existing texts to train its language generation skills. This process is called generative pre-training. The model is first pre-trained on a large corpus of text where it learns to predict the next word in a given context. Then the model is fine-tuned to a specific task, such as answering questions.
ChatGPT works on the principle of prediction. When you give it input, the model tries to predict what text should follow. This process is based on statistical patterns in the data the model has been trained on.
ChatGPT capabilities
ChatGPT is capable of performing a number of tasks, including:

Text generation:ChatGPT can generate text based on a given input. The text can vary from short answers to questions to long articles. This capability is useful for generating content for websites and blogs.
Context understanding:ChatGPT is able to understand the context of a conversation or text. This means that it can follow what is being discussed and adapt its responses to fit the context. This is important for creating more natural and relevant responses.
Answering questions:ChatGPT can answer questions based on the information available to it. This capability is useful for creating chatbots and other interactive applications.
Real-time interaction:ChatGPT is able to interact in real-time. This means it can respond to questions or comments instantly, allowing for a fluid and natural conversation.
Use in different applications:ChatGPT can be integrated into different applications and platforms. This means it can be used for various purposes such as customer service, learning tools, chatbots and much more.
Use of GPT-3 and GPT-4: ChatGPT uses the advanced GPT-3 and GPT-4 models. These models are based on machine learning technology and allow ChatGPT to generate more accurate and creative responses. The GPT-4 model delivers even more power and the ability to generate text that is even more natural and accurate.

How to use ChatGPT?
ChatGPT is a very flexible tool that can be used on different platforms and in different contexts. Here are some steps to get started using ChatGPT.
Create an account
The first step is to create the account itself on the OpenAI platform. Just go to the official website of the company OpenAI, where you then go to the ChatGPT application. Here you can create an account.

Go to https://chat.openai.com/auth/login to start creating a new account.
Click on the Sign up button.
You can sign up for ChatGPT using your email address, Google account, Microsoft account or Apple account. In this procedure, we will further demonstrate the option of using an email address.
Enter your email address and click Continue.
Create a password and click Continue. Your password must be at least 8 characters long.
Go to your email inbox and click on the verification link. OpenAI will send you an email with the verification link. Open the message from OpenAI and click on the link to verify your email address.
Enter your first and last name and click Continue.
Enter your phone number and click the Send code button. ChatGPT will send you a text message to verify your phone.
Enter the verification code and click Continue. Once your code is accepted, you will be logged in. Now you can start using ChatGPT to write code, essays, and more.

How to sign up for ChatGPT Plus
To log in to ChatGPT Plus and take advantage of everything the chatbot has to offer, follow these steps:

Create or log in to your OpenAI account. Visit the ChatGPT login page. Once you are there, you can log in to your account or create a new one.
Click on the 'Upgrade to Plus' button. Once you have logged into your account, you will be taken to the main chatbot page where you would normally start chatting. Instead, focus on the right panel and find the 'Upgrade to Plus' button. Once you've found the button, click it to move on to the next step.
Click on "Upgrade Plan" in the popup window. After you click on the "Upgrade to Plus" button, a popup will appear asking you a second time if you want to continue. If you are still ready to proceed after seeing the difference between the prices and features of the Free and Plus plans, click the green "Upgrade plan" button.
Complete your purchase. Once confirmed, you will be taken to a page to complete your purchase. This page requires all the usual information that a normal checkout would require, including your email, payment information and billing address.

Communication with ChatGPT
Once you have created an account, you can start communicating with ChatGPT. That is, you will specifically ask it questions or instructions and then you can read the answers that the model generates.
ChatGPT is able to generate natural language, answer questions, write essays, translate texts, write creative stories and much more. Interacting with ChatGPT is intuitive and simple, but there are certain strategies and techniques that can improve the quality of the interaction.
One of the keys to effective communication with ChatGPT is clarity and accuracy of queries. The more specific and clear your query is, the more likely you are to get a relevant and useful answer.
Furthermore, ChatGPT is able to monitor the context of a conversation, but is limited to a certain number of recent messages. It is important to keep in mind that if a conversation is too long, some earlier details may be lost.
Using ChatGPT capabilities
ChatGPT can be used for a number of tasks. It can generate text, answer questions, write articles and much more. Exactly how you use ChatGPT's capabilities depends on your specific needs and goals.
Using the GPT-3 and GPT-4 models
ChatGPT now supports both the GPT-3 model and the newer GPT-4 model. You can use these models according to your needs. The GPT-4 model offers improved text generation capabilities and better context understanding.

Settings
Setting up ChatGPT is a process that involves configuring various aspects to achieve the desired behaviour. Here is a general overview of which you can set up.
Changing the appearance of ChatGPT
Within ChatGPT, you can customize the appearance of the user interface. This appearance change applies to the colors, fonts, and layout of elements on the page.
The following procedure will show you how to change the appearance of ChatGPT:

Log in to your OpenAI account.
Click on your profile icon in the upper right corner.
Select Settings.
Under Appearance, select your preferred settings. You can choose different modes such as light, dark or customized.

Keep in mind that changes will take effect immediately and will affect all ChatGPT pages you work on.

Delete all conversations
In case you want to delete all conversations you have ever had with ChatGPT, follow these steps:

Log in to your OpenAI account.
Click on your profile icon in the top right corner.
Select Settings.
In the Conversations section, find the Delete all conversations option.
Click the Delete All Conversations button and confirm.

Please note that this deletion is permanent and cannot be undone. All conversations will be removed from your account and cannot be restored.
Activating Beta Features
You can activate beta features as follows:
Log in to your OpenAI account.Click on your profile icon in the top right corner.Select Settings.In the Beta Features section, find the features you want to activate.
Once activated, these features will be available in all your conversations with ChatGPT.

Turning off chat history
ChatGPT now allows users to turn off their chat history. This setting allows users to decide which conversations can be used to train OpenAI models. Conversations that start when chat history is turned off will not be used to train models and will not appear in the history sidebar. These controls are available in the ChatGPT settings and can be changed at any time.
When chat history is disabled, new conversations will be retained for 30 days and will only be reviewed when necessary to monitor for abuse before being permanently deleted.
Data export
ChatGPT has also introduced a new data export option that allows users to easily export their ChatGPT data and better understand what information ChatGPT stores. Once this feature is activated, you will receive an email with your conversations and any other relevant data.

Possibilities of use
ChatGPT is a powerful tool that can be used in many different contexts. Here are some of the most popular uses of ChatGPT.




Retrieved from


Description




ChatGPT as a chatbot


One of the most common applications of ChatGPT is as a chatbot. Chatbots can be used in a variety of contexts, including customer support, sales and marketing. ChatGPT can generate natural-sounding responses to user questions and instructions, making it ideal for interacting with people.




ChatGPT for text generation


ChatGPT can also be used to generate text. This can include writing articles, blog posts, marketing materials and much more. Using the GPT-3 and GPT-4 models, ChatGPT can generate text that is creative, engaging and persuasive.




ChatGPT for answers to questions


ChatGPT can also be used to answer questions. This can include answers to specific questions, such as facts or information, or answers to more complex questions that require analysis or interpretation.




ChatGPT for teaching and learning


ChatGPT can also be used in the context of teaching and learning. It can provide detailed explanations of concepts, answer student questions, and help in the preparation of study materials.




ChatGPT for integration with other platforms


ChatGPT can also be integrated with other platforms, such as WhatsApp, to provide enhanced features and capabilities. For example, ChatGPT can be used to generate replies to users' messages on WhatsApp.




Restrictions
While ChatGPT is a very powerful tool, it also has some limitations. Here are some of the most important limitations of ChatGPT.
Limitations in text generation
One of the main limitations of ChatGPT is that it can sometimes generate text that is incoherent or nonsensical. This is due to the fact that the model is trained on a large amount of text and does not have the ability to truly understand the context or meaning of the text it generates.
Limitations in understanding the context
Another limitation of ChatGPT is that it can sometimes have trouble understanding context. This can lead to the model generating responses that are unrelated or nonsensical in the context.
Limitations in the accuracy of information
ChatGPT may also have limitations in the accuracy of the information it generates. The model is trained on a large amount of text but has no ability to verify the accuracy or veracity of the information it generates.
Limitations in the use of the GPT-3 and GPT-4 models
While the GPT-3 and GPT-4 models offer improved text generation capabilities and better context understanding, they also have their limitations. For example, the models may have problems generating text that is too complex or difficult.
Limitations in integration with other platforms
Finally, although ChatGPT is flexible and can be integrated with many different platforms, the integration process can be challenging and complex.
The Future
ChatGPT is one of the most important research results in the field of artificial intelligence and machine learning. Its future is full of possibilities and promise that can fundamentally impact our interactions with technology and our understanding of AI.
Improved text generation capabilities
One of the main directions ChatGPT is heading is to improve its text generation capabilities. This includes improvements in understanding context and generating more accurate and relevant responses.
Extended integration options
Another direction ChatGPT is taking is to expand integration options. This includes integration with other platforms and applications, which will enable wider use of ChatGPT.
ChatGPT has the potential to change the way we interact with technology. Some of the possible future applications include:

Personal assistants: the ChatGPT could be used as an enhanced personal assistant, able to understand and respond to complex queries and requests.
Education: the ChatGPT could be used as an interactive learning tool, providing personalised learning materials and answers to students' questions.
Health: ChatGPT could be used to provide health information and advice, which could help improve access to health services.

Use of the GPT-3 and GPT-4 models
ChatGPT already uses the GPT-3 and GPT-4 models, which offer improved text generation capabilities and better context understanding. We can expect further improvements and extensions to these models in the future.
Greater accuracy and relevance
One of the main goals for the future of ChatGPT is to increase the accuracy and relevance of responses. This includes improvements in understanding context and generating more accurate and relevant responses.
Safety improvements
Security is a key concept that is becoming a central focus for the future development of ChatGPT. In an infinitely fast-paced and ever-changing digital world, it is essential that technology like ChatGPT is one step ahead in the fight against inappropriate and harmful content.
ChatGPT, not only prides itself on its artificial intelligence, but also embraces the role of security guardian. In the near future, major innovations and improvements aimed at detecting and blocking inappropriate and malicious content will be included. These efforts are key to providing a safe, respectful and acceptable environment for every user.
This is a complete overhaul of the way ChatGPT recognizes and responds to unwanted content - whether it's vulgar language, rude remarks, or any other type of content that could disrupt users' safety or comfort. To do this, ChatGPT will use even more sophisticated algorithms that will be able to recognize and filter such content to provide a safer and more enjoyable environment for everyone.
This commitment to increased security is not only based on technological necessity. It is also a matter of ethics, responsibility and respect for ChatGPT users. Security is not only a priority but a core value for ChatGPT.
The vision of ChatGPT therefore includes not only artificial intelligence, but also creating strong, safe and healthy digital spaces for communication. For ChatGPT, security is the cornerstone on which the entire platform is built.
Plugins - A new era of artificial intelligence
OpenAI introduces a revolutionary extension to its ChatGPT language model - plugins. These plugins allow the ChatGPT model to interact with external tools and provide new capabilities and features to users.

What are plugins?
Plugins are tools that the ChatGPT model can use for a variety of purposes. They allow the model to access information and features that would otherwise be unavailable. For example, a web browsing plugin allows the model to access information on the internet, while a code interpretation plugin allows the model to perform mathematical calculations or analyze data.
How do I access the plugins?
Users with a ChatGPT Plus subscription can activate the plugins in the "Beta Features" section of the settings. Access to the plugins was released on May 12, 2023 and will be gradually expanded over the course of the week.
How do the plugins work?
The ChatGPT model learns when and how to use plugins based on user queries. If needed, users can ask the model to explicitly use a plugin.
How do I create a plugin?
Developers can create their own plugins and submit them for approval. OpenAI documentation is available for this.
What plugins are available?
Some of the first plugins that have been created include plugins from Expedia, FiscalNote, Instacart, KAYAK, Klarna, Milo, OpenTable, Shopify, Slack, Speak, Wolfram, and Zapier. OpenAI also hosts two custom plugins: a web browser and a code interpreter.
What are the benefits and risks of plugins?
By connecting external data to language models, these models can be more useful and users can better assess the credibility and accuracy of the information. However, there is a risk that plugins could increase security challenges by performing malicious or unintended actions. OpenAI has implemented several safeguards to minimize these risks.

Conclusion
ChatGPT is a revolutionary tool that brings new possibilities in text generation and communication. It uses advanced GPT-3 and GPT-4 models to generate accurate and relevant responses based on context.
Summary
ChatGPT is a tool that can be used in many areas including customer support, marketing, education and many more. Although it has its limitations, such as its inability to fully replace human writers, its benefits and capabilities far outweigh them.
Future direction
ChatGPT is constantly evolving and improving. In the future, we can expect further improvements in text generation, expanded integration options, and increased accuracy and relevance of responses. Security is also a key area that ChatGPT will focus on in the future.
Final thoughts
ChatGPT is a tool that brings new possibilities in text generation and communication. Its use can bring huge benefits, but it is important to be aware of its limitations and always use it with safety and ethical considerations in mind.]]></content:encoded>
                
                                    <category><![CDATA[Artificial Intelligence]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/a8/a80beb2f-649c-49ea-a6e8-e9ed69fbaa1f/conversions/chatgpt-ultimate-guide-full.jpeg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[How to run a new Laravel application on Homestead]]></title>
                <link>https://www.pavelzanek.com/en/blog/new-laravel-application-homestead</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/new-laravel-application-homestead</guid>
                <pubDate>Sun, 05 Dec 2021 00:00:00 +0100</pubDate>

                                    <description><![CDATA[Learn how to set up and run a new Laravel application on Homestead. This guide will walk you through the entire installation and configuration process.]]></description>
                
                                    <content:encoded><![CDATA[In today's article, I will focus on creating/installing a new Laravel application in a local environment.

Prerequisites


Windows 10
Installed Laravel Homestead (Vagrant + VirtualBox)
Laravel Installer


In Brief

Before we look step by step at how to install a new Laravel application in Windows 10 using Homestead and the installer, let's create a small roadmap:


Set up the hosts file
Configure Homestead
Start a new installation using the installer
Launch Homestead with the new configuration


Setting Up the Hosts File

There are several ways to edit files, from using the command line to using something as simple as Notepad. We don't need to play professionals, so Notepad will suffice (wink wink).

So, we open Notepad with the "Run as administrator" option.



In Notepad, we choose File->Open… (CTRL+O) and go to the folder "C:\Windows\System32\drivers\etc". Remember to display all files if you only see .txt files (or see nothing, like me):



We see all the files in the folder and open the "hosts" file.



Now we add:

...
192.168.10.10 your-laravel-application.test
...

Thus, we have mapped the IP address of our future Homestead to a URL. If we enter the URL into the browser later, the requests will be directed to Homestead – let's set it up.

Setting Up the Homestead.yaml File

Go to the folder where you have Homestead installed (in my case "C:\Users\***\Homestead") and open (again you can in Notepad without the need to run the file as an administrator, or in your favorite IDE) the Homestead.yaml file.

Take a look at an example of what your Homestead.yaml could look like.

---
ip: "192.168.10.10"
memory: 512
cpus: 1
provider: virtualbox
ssl: true

authorize: c:/Users/***/.ssh/your-public-key.pub

keys:
    - c:/Users/***/.ssh/your-private-key.ppk

folders:
    - map: d:/laravel-websites
      to: /home/vagrant/code

sites:
    - map: your-laravel-app.test
      to: /home/vagrant/code/your-laravel-app.test/public
      php: '8.0'

databases:
    - your_db_to_application

features:
    - mysql: false
    - mariadb: true
    - postgresql: false
    - ohmyzsh: false
    - webdriver: false

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

Several things are worth noting, let's take a look at them.


IP address – the same one we used in the hosts file
folders – we need to map where the application is located. In my case, I use the "D:\" drive, in which I have a "laravel-websites" folder. This entire folder gets to Homestead under "/home/vagrant/code".
databases – we can directly create a db for our application
additionally, I showed how you can access Homestead under SSH.


Installing Laravel Using the Installer

Now we know on which URL we will build the application. We also know that if we enter the URL into the browser, we will get to Homestead thanks to the mapping. Homestead is then configured to download content from the local "D:\laravel-websites" folder and place it in "/home/vagrant/code". However, we also know that we are specifically looking for /home/vagrant/code/your-laravel-app.test/public. So we need to install a Laravel application.

So, we go to "D:\laravel-websites" using the command line and run:

laravel new your-laravel-app.test

After completion, the result should end up something like this:



Launching Homestead with New Configuration

Now we need to start Homestead including our new configuration. So, go to the location where you have Homestead installed (in my case "C:\Users\***\Homestead") in the command line and run:

vagrant up --provision

Alternatively, if you already have Homestead running, you can use (so you don't have to turn off Homestead via "vagrant halt")

vagrant reload --provision

It's important that the --provision switch is used, which launches Homestead with the new configuration.

TIP

If you want to log into Homestead using SSH, just run from the installed folder with Homestead:

vagrant ssh

Then you can get to your application:

cd code/your-laravel-app.test

In Homestead, in the project folder, you can perform various commands (migrations, generation of assets, installation of packages, etc.).

In Conclusion

Now you just need to add the project to your IDE and edit the .env file. Once you configure it, you can enter the URL of the project in the browser and see the new Laravel application. Then just create something great.]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/33/3363c3ba-22ab-4c66-9425-a8685a29d71c/conversions/new-laravel-application-homestead-full.jpeg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Laravel Application Localization]]></title>
                <link>https://www.pavelzanek.com/en/blog/laravel-application-localization</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/laravel-application-localization</guid>
                <pubDate>Sat, 20 Nov 2021 00:00:00 +0100</pubDate>

                                    <description><![CDATA[Learn how to localize a Laravel application. This guide covers everything from setting up language files to switching languages.]]></description>
                
                                    <content:encoded><![CDATA[The text provided describes a simple method for localizing a Laravel application, focusing on translating parts of the application rather than content stored in the database or localizing URLs. The guide details how to set up translations for strings appearing in the Laravel application template.


Tested in: Laravel 8
Stack: Jetstream / Livewire + Blade/Tailwind CSS, but can be used anywhere with front-end modifications
Documentation: https://laravel.com/docs/8.x/localization


Logic

The logic is quite straightforward, with no need for database intervention.

Language Settings

config/app.php:

...
'locales' => [
        'en' => 'English',
        'cs' => 'Czech',
 ],
...

Middleware Language

app/Http/Middleware/Language.php:

&lt;?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;

class Language
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {        
        App::setLocale($request->language);
        URL::defaults(['language' => $request->language]);
        $request->route()->forgetParameter('language');
        return $next($request);
    }
}

Adding Middleware to the Kernel

app/Http/Kernel.php:

...
protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\Language::class, // Localization
        ],

        ...
];
...

Routes in web.php

routes/web.php:

...
Route::group([
    'prefix' => "{language}", 
    'where' => ['language' => '[a-zA-Z]{2}']
    ], function () {

    ...

});
...

LanguageController.php Controller

app/Http/Controllers/LanguageController.php:

&lt;?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;

class LanguageController extends Controller
{
    public function switchLang(Request $request, $lang)
    {
        // $urlParts[1] == current lang
        $urlParts = explode('/', str_ireplace(array('http://', 'https://'), '', url()->previous()));

        $newUrl = str_replace(
            '/' . $urlParts[1] . '/', 
            '/' . $lang . '/',
            url()->previous() 
        );

        App::setLocale($lang);
        URL::defaults(['language' => $lang]);
        return redirect()->to($newUrl);
    }
}

Adding the Controller Route to web.php

routes/web.php:

...
Route::get('lang/{lang}', [App\Http\Controllers\LanguageController::class, 'switchLang'])->name('langSwitcher');
...

RouteServiceProvider.php

app/Providers/RouteServiceProvider.php:

...
public const DASHBOARD = '/en/dashboard';
...

Creating a Language Switcher

Example for use in the stack: Laravel, Jetstream – Livewire + Blade, Tailwindcss

resources/views/navigation-menu.blade.php:

Desktop

...
&lt;!-- Language Dropdown --&gt;
&lt;div class="ml-3 relative"&gt;
    &lt;x-jet-dropdown align="right" width="48"&gt;
        &lt;x-slot name="trigger"&gt;
            &lt;span class="inline-flex rounded-md"&gt;
                &lt;button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition"&gt;
                    @lang(config('app.locales')[App::getLocale()])

                    &lt;svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"&gt;
                        &lt;path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /&gt;
                    &lt;/svg&gt;
                &lt;/button&gt;
            &lt;/span&gt;
        &lt;/x-slot&gt;

        &lt;x-slot name="content"&gt;
            &lt;!-- Language Switcher --&gt;
            &lt;div class="block px-4 py-2 text-xs text-gray-400"&gt;
                {{ __('Select language') }}
            &lt;/div&gt;

            @foreach (config('app.locales') as $lang =&gt; $language)
                @if ($lang !== App::getLocale())
                    &lt;x-jet-dropdown-link href="{{ route('langSwitcher', $lang) }}"&gt;
                        @lang($language)
                    &lt;/x-jet-dropdown-link&gt;
                @endif
            @endforeach

        &lt;/x-slot&gt;
    &lt;/x-jet-dropdown&gt;
&lt;/div&gt;
...

Responsive Version

...
&lt;div class="mt-3 space-y-1"&gt;
    &lt;div class="border-t border-gray-200"&gt;&lt;/div&gt;

    &lt;div class="block px-4 py-2 text-xs text-gray-400"&gt;
        {{ __('Select language') }}
    &lt;/div&gt;
    
    @foreach (config('app.locales') as $lang =&gt; $language)
        @if ($lang !== App::getLocale())
            &lt;x-jet-responsive-nav-link href="{{ route('langSwitcher', $lang) }}"&gt;
                @lang($language)
            &lt;/x-jet-responsive-nav-link&gt;
        @endif
    @endforeach

    &lt;div class="border-t border-gray-200"&gt;&lt;/div&gt;
&lt;/div&gt;
...

Adding Translations

For example, resources/lang/cs.json:

{
    "Dashboard": "Nástěnka",
    "Select language": "Vyberte jazyk",
    "Czech": "Čeština",
    ...
}

Result

Czech Version:


English Version:


Tip

If you use Jetstream with Livewire as in the example and want to localize the default routes, then a few more minor adjustments are necessary.

From the /vendor/jetstream/routes/ folder, copy the routes to your routes. The file can then look like this (routes/web.php):

&lt;?php

use Illuminate\Support\Facades\Route;
use Laravel\Jetstream\Http\Controllers\CurrentTeamController;
use Laravel\Jetstream\Http\Controllers\Livewire\ApiTokenController;
use Laravel\Jetstream\Http\Controllers\Livewire\PrivacyPolicyController;
use Laravel\Jetstream\Http\Controllers\Livewire\TeamController;
use Laravel\Jetstream\Http\Controllers\Livewire\TermsOfServiceController;
use Laravel\Jetstream\Http\Controllers\Livewire\UserProfileController;
use Laravel\Jetstream\Http\Controllers\TeamInvitationController;
use Laravel\Jetstream\Jetstream;

Route::get('lang/{lang}', [App\Http\Controllers\LanguageController::class, 'switchLang'])->name('langSwitcher');

Route::get('/', function () {
    return redirect()->route('login');
});

Route::group([
    'prefix' => "{language}", 
    'where' => ['language' => '[a-zA-Z]{2}']
    ], function () {

    Route::group(['middleware' => config('jetstream.middleware', ['web'])], function () {
        if (Jetstream::hasTermsAndPrivacyPolicyFeature()) {
            Route::get('/terms-of-service', [TermsOfServiceController::class, 'show'])->name('terms.show');
            Route::get('/privacy-policy', [PrivacyPolicyController::class, 'show'])->name('policy.show');
        }

        Route::group(['middleware' => ['auth:sanctum', 'verified']], function () {
            Route::get('/user/profile', [UserProfileController::class, 'show'])
                        ->name('profile.show');

            if (Jetstream::hasApiFeatures()) {
                Route::get('/user/api-tokens', [ApiTokenController::class, 'index'])->name('api-tokens.index');
            }

            if (Jetstream::hasTeamFeatures()) {
                Route::get('/teams/create', [TeamController::class, 'create'])->name('teams.create');
                Route::get('/teams/{team}', [TeamController::class, 'show'])->name('teams.show');
                Route::put('/current-team', [CurrentTeamController::class, 'update'])->name('current-team.update');

                Route::get('/team-invitations/{invitation}', [TeamInvitationController::class, 'accept'])
                            ->middleware(['signed'])
                            ->name('team-invitations.accept');
            }
        });
    });

    Route::group(['middleware' => ['auth:sanctum', 'verified']], function () {
        Route::get('/dashboard', function () {
            return view('dashboard');
        })->name('dashboard');
    });

});

For instance, if we modify the route for displaying the profile, like this (routes/web.php):

...
// Old value: /user/profile
Route::get('/profile', [UserProfileController::class, 'show'])->name('profile.show');
...

If we make the above change, the profile display will be available on our route /profile, and we can also use the default route /user/profile (loaded from the package – laravel/jetstream/routes/livewire.php). If we want to disable the default routes, then we must modify JetsreamServiceProvider.php (app/Providers/JetsreamServiceProvider.php).

...
public function register()
{
    Jetstream::ignoreRoutes();
}
...]]></content:encoded>
                
                                    <category><![CDATA[Laravel]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/4a/4ac45210-b41b-4585-aef0-aeba95903141/conversions/laravel-application-localization-full.jpeg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Page indexing in search engines]]></title>
                <link>https://www.pavelzanek.com/en/blog/page-indexing</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/page-indexing</guid>
                <pubDate>Thu, 30 Nov 2017 00:00:00 +0100</pubDate>

                                    <description><![CDATA[Find out how search engines index pages, what factors affect indexing and how to ensure your pages are properly indexed.]]></description>
                
                                    <content:encoded><![CDATA[What is page indexing
Website indexing is a process where a search engine bot visits you, tries to go through all the content, and stores it in its database (indexes it). When you search for "something" using a search engine, it doesn't start searching the entire internet. The search engine looks in its database and offers you relevant results for your query - so the pages in the search result must be indexed by it. If the search engine doesn't have them stored in its database, it's clear that it won't display them. You can think of the database as a kind of library of websites from which the search engine finds the best answer to the searched query. Therefore, it is important to focus on website indexing in search engines for every project.
Poor website indexing
As usual, with websites, it is possible that search engines don't know about all the pages you want to display in search results. Then you can lose visitors and may not cover a segment that is beneficial for your business. Imagine, for example, that you might not have your main page, e-shop category, blog articles, etc., in the search engine index. And if the search engine doesn't have them stored in its database, it can't display them in search results.
Many websites commonly use non-indexing of pages - you don't want to display pages in search results. It can be, for example, thank you pages, an e-shop cart, user sections, and much more.
However, sometimes you want to index a page, you send the page URL to search engines for their crawling bot to evaluate. You might have it in a sitemap or even manually send it for indexing - "Add Page" on Seznam and "Submit URL" on Google. However, it can happen that the search engine may decide not to index it anyway. Then it is important to find out what might be the reason why the search engine doesn't want to display it and what prevents it from indexing.
Analysis of website indexing
There are many ways to check the status of indexed pages. Look at the basic steps I follow.
Checking page indexing using the site operator
I tried to generally write a guide on how you can also check the status of indexing your websites. Since this question was asked quite often, I created an answer to it in the SEO clinic, where you can also find other SEO tips. It's mainly about comparing the number of URLs you want to display in search results with the number of pages returned using the site operator.
Checking page indexing using sitemap and Marketing Miner
If you have created a sitemap with URLs that you want to display in search results, we can specifically find out which pages are being indexed and possibly those that are not displayed in the search. First, before checking the display of pages, see if your sitemap really only contains URLs that you want to send to search results.
For the actual analysis of the pages sent through the sitemap, I use Marketing Miner, which contains a useful Fulltext Index Checker function.

Go to the Marketing Miner website and log in
Choose that you want to create a "New report"
To the question of what query you want to insert, choose "URL"
Choose "Sitemap / RSS" and enter the sitemap URL, you can rename the report and choose "Go to miners"
Choose the Fulltext Index Checker among the miners

TIP: You can also choose URL Indexability - you will find out which URLs are indexable, which are canonicalized, or which are prohibited in robots.txt
Marketing Miner will show you which URLs are indexed and which are not. In my opinion, this is the fastest and simplest way to create a quality analysis of page indexing.
Checking page indexing, for example, using Google Analytics or Google Data Studio
In general, but not exactly, you can also determine page indexing through landing pages - from organic search. You can filter landing pages directly in the Google Analytics analytical tool, or you can create your own overview using Google Data Studio. Just download the reports for a certain period and compare them with the URLs sent in the sitemap.
If there was traffic on the landing pages from search engines, then they logically appear in search results. And if the traffic is zero, then it's worth checking why.
Why might pages not appear in search?
There can be several reasons why web pages do not appear in search results. Sometimes the cause can be visible at first glance, but sometimes you have to focus more deeply on the issue of poorly indexing pages.

Check if the page contains a meta tag with the "noindex" parameter - used to prohibit page indexing.
Check if the page is blocked through robots.txt (even via robots.txt it is possible to disable indexing of pages, but this file should not be used for this purpose).
Check if the page has a simple URL that is not obstructing indexing for search engines (hashtags in URL, parametric URLs)
Is the page internally linked and leads to a working link?
Are there any redirects on the target URL? Or are there many of them?
Is the page listed in the sitemap?
Isn't the page duplicate to an already created page on your website? Does the search engine have a reason to also display it in search results?
Page quality or penalty (see below)

TIP: Support the page by linking it with backlinks. There can be many more reasons, but these are the most common causes I encounter.
Page usefulness - is the page beneficial for users?
If the page is not indexed, even though it has all the prerequisites to be indexed, then another option is to check the content of the page. In addition to not being duplicate with another page, see if the page content is useful for users. If so, then check if you are linking to relevant websites (outgoing links), if you don't have a lot of generated texts on the page, if you don't display different content to search engines than to users, and other possible shortcomings that could bother search engines.
Once I also encountered that websites used article ratings, but this rating was generated - so it was not added by the user himself. Google then penalized the website for these pages and stopped displaying them.
Penalties
The worst case that can happen is a penalty. You can find out about a possible manual penalty directly in Google Search Console, then in the "Manual Actions" section.
It can also happen that you have malware on your pages. You can then find it in GSC in the "Security Issues" section.
How to quickly index newly created pages
If you want to quickly index the content of your websites, there are procedures to speed up indexing. If you create a page that you want to display in search results, then:

send the page manually for indexing

Google &ndash; URL Inspection tool
Seznam - Add page


have the page in the sitemap, which you send through services

Google Search Console
Seznam Webmaster



In Google Webmaster Tools (Google Search Console), you can also use another function - Fetch as Google. Through the tool, you request a rendering of the web page, and if no problem is found, you can immediately request page indexing. For example, you can find out which resources Googlebot couldn't download.

In conclusion
There can be several reasons why a page may not be indexed correctly. However, make pages primarily for users and not for search engines. Then pay attention to other technical prerequisites that search engines expect and you won't cause them problems. If you decide to use the noindex parameter somewhere, then check the changes made. There is nothing worse than deindexing pages and then losing traffic.]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/76/764471df-290d-4721-90b8-ec93bb35e2ae/conversions/page-indexing-in-search-engines-full.jpg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Automatically generated content]]></title>
                <link>https://www.pavelzanek.com/en/blog/automatically-generated-content</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/automatically-generated-content</guid>
                <pubDate>Sat, 19 Aug 2017 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Find out what automatically generated content is, how search engines evaluate it and how to avoid being penalized for using it.]]></description>
                
                                    <content:encoded><![CDATA[What is automatically generated content and how to use it in SEO
Automatically generated content is a type of content not created by a user, but by the program itself. It can save you time and money, however, automatically generated contents are often not of high quality. It's not exactly a forbidden technique, but if you overdo it, search engines may penalize you.
As we continue to move forward with time, we try to save work and time. Therefore, we try to automate processes wherever possible. Thus, you can also use automation in content creation.
However, I must point out that I recommend using automatically generated content for projects that involve thousands of pages and where it is not possible to create texts manually. If you had to describe thousands of pages, then your work would be inefficient and you would unnecessarily lose time instead of optimizing more important steps.

Possibilities of using generated texts
Automatically generated content on websites can be used in several places. For example, imagine you have thousands of products for which you need to add descriptions. Initially, it is always necessary to focus on what we can use. For instance, our online store sells T-shirts. For each T-shirt, we have parameters like color, style, sleeve length, material, price, etc. Of course, each product has a unique name. Once you have gathered all the information that can be found for all products (which is why it's necessary to have well-managed products), then you are ready to meet with an SEO specialist. The SEO specialist will advise you on which parameters are sought after and what keywords would fit well into the product description. Imagine the SEO specialist advises you to emphasize the material of the T-shirts. For example, they might recommend inserting phrases like "cotton T-shirts" (material + category) into the generated content.
TIP: The most searched parameters (phrases) that will appear in the automatically generated content can be internally linked to a relevant page (e.g., a product description containing the phrase "cotton T-shirts" can also be a link to a listing of all T-shirts made of cotton material). This shows that the specific product listing is really important to you and the links will support it.

Template for automatically generated content
Once you know what phrases, parameters, and combinations are searched for, you can move on to working with a copywriter to start designing a template. Since we have gathered the product parameters, we can use them as variables and incorporate them into the text template. Look at how such a template for automatically generated content might look like when combining SEO with copywriting: "A quality [gender specification] [product name] [sleeve length] is suitable for everyday wear. You will surely love the [material] T-shirt in [color] color. The [print] T-shirt from the [brand] brand is available for an amazing [price]." "A quality men's XYZ T-shirt with short sleeves is suitable for everyday wear. You will surely love the red cotton T-shirt. The no print T-shirt from the Adler brand is available for an amazing 149 CZK."
As you can see, automatically generated content can be quite simply created. However, it is important that the text, along with the variables, makes sense. From this example, you can see that the same template could be used for page descriptions (meta description). And because you discussed the parameters with an SEO specialist, the searched words will appear here – and if the searched phrase is the same as the page description (meta description), then the word will be bolded in the search results, which can increase click-through rate – and thus bring more visitors to the website.
First, prepare well and then think of texts that make sense to users!
Look at the basic examples where automation can be used.

Page titles (title)
Meta data – page descriptions
Descriptions in categories/sections
Descriptions on product pages
Additional information to your articles
Etc.

Thus, it does not only have to be descriptions, thanks to generated content you can also add, for example, a sentence to articles like: "The article "[article title]" by author [author name] was published on [publication date of the article]. It falls under the category [category name] and contains tags [list of tags]. It already has [number of comments] comments and readers rate it at [rating/number of stars] stars. The article was updated on [article update date]."
As I mentioned at the beginning, automatically generated texts are usually not very unique or high quality. Still, they can save you effort and work. If you have implemented generated content on websites (whether you did it yourself or with the help of programmers), then I especially recommend reviewing the most important pages – make sure the text really makes sense.

Pareto Principle, SEO, and Automatically Generated Content
On the most visited pages, eventually replace automatically generated content with manually written quality text. You might have heard of the "Pareto Principle" – it's about the 80/20 split. This principle can also be applied to e-commerce websites. In most websites I have dealt with, there's a wide range of products, but the most sold items usually only make up 20% of all products. The remaining 80% of products are not as business-critical. Therefore, within the scope of SEO, but also in terms of content strategy, determine the 20% of products that are business-critical for you and then optimize them manually. I don't mean to say that automatically generated content won't help you, but it definitely will never achieve the same results as quality text with added value for the user.]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/77/773ae472-1a9f-4f95-a2da-591e27f1dd51/conversions/automatically-generated-content-full.jpeg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Correct landing page for SEO]]></title>
                <link>https://www.pavelzanek.com/en/blog/correct-landing-page</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/correct-landing-page</guid>
                <pubDate>Wed, 31 May 2017 00:00:00 +0200</pubDate>

                                    <description><![CDATA[Find out what a landing page is, how to correctly design it for SEO and how to ensure it drives relevant traffic.]]></description>
                
                                    <content:encoded><![CDATA[I still encounter cases (most often with e-shops) where websites return incorrect landing pages. If you&nbsp;return an irrelevant landing page for specific queries, you may be losing visitors, or there may be a high bounce rate and low conversion ratio on the pages.
Imagine that you enter the query "notebook lenovo ssd" into a search engine. You expect websites offering relevant products to appear in the search results, but the opposite is true. Look at the screenshot where I marked why the landing pages are not relevant for the query.

As you can see, the search results include links to websites that mainly offer only one of the parameters I entered for the notebooks. Here you can see that people might skip these results and continue searching further. It is also necessary to say that websites appearing in top positions can respond with a relevant page &ndash; they have the specific type of notebooks on offer.
At the same time, this example clearly shows that being in the first position is not always a win. You may appear in top positions for queries, but if you return the wrong landing page, you might not have as high a click-through rate as a website below you offering a relevant landing page. Then it's up to the search engines to notice that the website below you offers a more relevant response and over time may reassess the positions and move you to worse positions than you are in now. Meanwhile, the website with the relevant landing page can move to the forefront of search engines.
How to find out which landing page I return for a query
If you are interested in what landing pages you return in search results, there are several possible solutions to analyze their current state. The analysis itself is quite simple, but optimizing websites to return the correct landing pages for people's queries is more difficult. If you want to start analyzing, you must meet certain prerequisites &ndash; or you can decide how to arrive at the result. Here are the options for analyzing landing pages:

using Google Analytics

directly in Google Analytics
using external tools &ndash; Google Data Studio, Power BI, &hellip;


using tools to remeasure positions + determine the landing page

Marketing Miner
Collabim



There are more ways to proceed, but in my opinion, these are the simplest ways to find out whether you are returning the correct or wrong landing page for a specific query. In this article, I will focus on method number 1 &ndash; i.e., analysis using Google Analytics. However, if there is interest, I will create a guide for you in Google Data Studio, where you can better illustrate the results for easier data analysis.
The procedure could also be used for other marketing sources, but we will focus on organic search results (i.e., the unpaid part of search results).
Google Analytics &ndash; Does the search engine return the correct landing page?
Let's look together at how you can use Google Analytics to get an overview of what landing pages you return for specific queries in search engines.

Log in to Google Analytics
Select the website you want to analyze
In the left menu, select "Acquisition" -&gt; "Overview"
Choose "Organic Search"
Add a secondary dimension &ndash; "Landing Page"
We can filter the data using an advanced filter from "np &ndash; /"; (not provided)

choose an advanced filter
exclude from keywords everything you don't want to be included in your analysis




Now you should have an overview of keywords and the associated landing page for organic only. You can check if you are responding with a relevant landing page to queries. You can also see if you have a higher percentage of exits and lower conversion than on relevant landing pages &ndash; this is usually the case for most websites.
If you discover that you are returning the wrong landing page, you can start optimizing your websites. Thanks to this, you can

increase the number of visitors from search engines
reduce the bounce rate
increase the conversion ratio and thus increase revenue/profits
increase the time spent on the page

Why I don't return a relevant landing page
If you want to focus on the reasons why the search engine does not return the correct landing page, then you will need to work on analyzing the current state of your websites.
There can be several reasons why a search engine returns a different landing page than you wish. Let's look at the points that can affect the returning landing page:

poor internal linking of websites
fragmentation of strength within link-building activities (e.g., you direct links with bad anchor texts, backlinks lead to different pages than they should -&gt; you increase the strength of other pages than those needed)
search engine's lack of knowledge &ndash; it doesn't know about the correct landing page -&gt; there could be a noindex set on the page, a ban in robots.txt, parameterized URL of the landing page,&hellip;
or perhaps the most serious problem &ndash; do you have the landing page created? ?

There can be many more reasons, but these points are always a good starting point. Each project may have a completely different reason.
TIP: For visualizing internal website linking, you can use the Gephi tool.
TIP: You can check if you return the correct landing page for different search engines &ndash; for example, you may return the correct landing page on Seznam, but on Google, the landing page may already be irrelevant.
Try the mentioned method to discover whether you respond with landing pages to people's queries. In a short time, you can uncover possible pitfalls of your websites.]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/8b/8b4bcef0-1334-4307-84b1-12bb3168f69f/conversions/correct-landing-page-featured-img-full.jpeg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Data collection – keyword research – Part 1]]></title>
                <link>https://www.pavelzanek.com/en/blog/data-collection-keyword-research-part-1</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/data-collection-keyword-research-part-1</guid>
                <pubDate>Sat, 22 Apr 2017 00:00:00 +0200</pubDate>

                                    <description><![CDATA[If we decide to conduct a keyword analysis, we must start with data collection, which we will explore in this article.]]></description>
                
                                    <content:encoded><![CDATA[Data on "Paper"
There are several tools that can help us, but I strongly recommend starting with a piece of paper. Initially, it's appropriate to write down all the queries/phrases/keywords people are most likely to use to find (visit) you, and these words should also reflect your website. This is often an overlooked part &ndash; in agencies, I have seen them immediately move to using tools. However, if you are behind a project, you have much more knowledge about your field and can also pinpoint how people are searching for you. Besides listing relevant words that come to mind, you can also make an overview of how people search for the field when they have knowledge (here you list phrases with certain industry terminology) and at the same time if they lack knowledge (layman's and non-professional terms). You can then make overviews in synonyms (descriptions of words) - USA/America; Belts/Straps; Car/Toy Car/Automobile/Passenger Car.
Expanding "Paper" Data
As a second point in data collection, it's important to expand our expressions with other relevant terms. Here we will first use tools that are free. Specifically, this refers to the &ldquo;Keyword Planner&rdquo; in Google Adwords and &ldquo;Keyword Suggestions&rdquo; in Seznam Sklik. Personally, I proceed as described below, but it depends on how you choose to proceed.

After logging into Sklik, I first start asking the keyword suggestion tool about the queries I wrote down on paper. The next steps depend on the project and the specific keyword. From the suggestions, we can choose words that are relevant and then download them.

Another option is to download all the suggested words (which will include irrelevant words) and in the next part (when we clean the data) we will get rid of the irrelevant words. It always depends on you, which step is more beneficial for you &ndash; here some experience is needed to recognize which step is better for you. With the first method, we don't have to clean the data from "ballast" (irrelevant words), in the second method we get irrelevant keywords into the dataset, which could be used in PPC as so-called "excluding words" in advertising campaigns. If we download data from Sklik, I recommend keeping all the data that Seznam offers &ndash; average CPC, competition, monthly search volume in specific months, average monthly search volume for the last 12 months, etc. We might not need this data eventually, but it can be useful for identifying trends according to the season of individual KWs. For example, I collect this data through other websites (like Collabim, but more on that later).
The same method can be used in Google Adwords in the keyword planner. However, I recommend entering more general terms into Google Adwords and more specific queries into Sklik. A great advantage of the planner (GA) is that we can ask for multiple queries at once, unlike Sklik, where we can only enter one key phrase. The planner also has a function to obtain data on search volume &ndash; you can enter, for example, 500 keywords, let them run through the planner, and then it will determine the search volumes. Then Adwords can be used to expand keywords &ndash; if we give it about 10 keywords, it is able to expand them with other words and thus we have a larger dataset with additional words after downloading. Keyword planner tools and keyword suggestions are definitely among the main and most important sources for data collection and should not be overlooked. You will get the most words, which you will surely utilize.
Google Analytics
Do you already have websites in operation and are they linked with Google Analytics? Then you have another option for reaching more phrases. From Google Analytics, you can export keywords &ndash; just select organic as acquisition in GA and then simply download all the phrases.

Open GA
Choose "Acquisition" &ndash; "All Traffic" &ndash; "Channels"
Select "Organic Search"
Filter out "not set" and "not provided" KW

Click on "advanced" (next to the search)
"Exclude" - "keyword" - "contains" - "np -/ (not provided) and (not set)"


Change the number of displayed rows (see info below)
Export data (at the top)

Just a note that if you export, Analytics can only export the current page (thus, if you have a total of 1,000 keywords on the page, you will download exactly 1,000 when downloading, even though you might have, for example, 20,000 in the entire GA overview &ndash; so you would be downloading 20 documents). Analytics still can't export all KWs if they are not on one page. For large datasets, I recommend selecting 5,000 items for display and then downloading page by page. Google Analytics gives us further valuable information about specific keywords, if properly set up &ndash; e.g., bounce rate, conversion ratios, new visits, but especially revenues and the number of transactions (which we will use when determining priorities &ndash; pairing data from external sources will be discussed after cleaning datasets from irrelevant phrases). However, you must have Analytics properly linked and set up.
Google Webmasters Tools
Another option for obtaining more data on how people came to us is to look into Google Webmasters Tools. If you have your website linked with this service, then:

Go to GSC.
Choose your website.
In the left menu, select search traffic.
Choose search analytics.


I recommend going through this tool and getting an idea of how this tool works. You can also select a different time period &ndash; unfortunately, you can only select data for the last 90 days. If you use GSC, I definitely recommend linking it with Google Analytics. Then you will have data for a longer period. Google search console also unfortunately shows only 1,000 keywords / phrases in the overview.
TIP: Download this data and combine it so that it follows each other. Data and data work is often neglected by Czech websites.
Keyword Suggester
We definitely must not overlook keyword suggestions from search engines. When you start typing a phrase, search engines will show you a box with expanded data on how we can ask the search engine. These phrases can also be useful for us and we should not overlook them. An online tool keywordtool.io can help us, where you just need to enter a keyword, search for more KWs and then download the found data. I use the tool in its free version, in the paid version there are additional data from adwords &ndash; search volume, CPC, and competition (but I don't use the paid version &ndash; I can't evaluate it).
Competition
Is the competition by any chance using different labeling of "the same thing" that you offer? Does the competition have differently named categories? This and much more needs to be analyzed and only when working with the analysis of keywords will we recognize what names we will use (whether the same as the competition or different). Last but not least, we monitor the competition so that we don't forget and omit important segments and queries. We can also use tools like Xenu/ScreamingFrog, where you just need to enter the URL address of the competition and the tool will find valuable information about how the competition uses titles, descriptions, headings, etc., where we find keywords. Marketing Miner and Ahrefs are also worth mentioning for how to find the competition.
Expanding Keywords
Another way to get more relevant queries (however, without finding out whether they have any search volume, impressions, etc. &ndash; this can be dealt with later when we talk about Collabim or Marketing Miner) is to use the &ldquo;keyword expansion&rdquo; tool. Just enter the main keyword, then individual properties, and the tool will take care of their combination.
Google Adwords and Seznam Sklik
Let's look at search phrases from advertising campaigns. This way, we also learn how people wrote queries into search engines, ads were displayed and thus we have another source for obtaining more data.
So far, we have obtained data from various sources. Now it's time to group them. So we open Excel or another spreadsheet tool and insert only the keywords into it. If we came across data with additional information during collection, we keep it separately for now. So now we will work only with the dataset of keywords.
Note: If you want to work with phrases with excessive search volume or impression (or according to your rules &ndash; depends on what additional data you downloaded), I recommend creating another document here and separating the sub-limit phrases into it.]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/6b/6bf2bdf9-374a-4d40-8970-2a1c486feb80/conversions/keyword-research-featured-img-full.jpeg" type="image/jpeg" />
                            </item>
                    <item>
                <title><![CDATA[Keyword Research – The Complete Guide]]></title>
                <link>https://www.pavelzanek.com/en/blog/keyword-research</link>
                <guid isPermaLink="true">https://www.pavelzanek.com/en/blog/keyword-research</guid>
                <pubDate>Sat, 22 Apr 2017 00:00:00 +0200</pubDate>

                                    <description><![CDATA[&quot;Keywords? Just stuff them into the text, and I&#039;m optimized!&quot; Well, it really doesn&#039;t work like that. Modern keyword research is about discovering how people search in your field.]]></description>
                
                                    <content:encoded><![CDATA[Keyword Research - The Complete Guide
"Keywords? Just stuff them into the text, and I'm optimized!" Well, it really doesn't work like that. Maybe it did a few years ago. Nowadays, if you want to work with keywords, you need to learn how to find and use them correctly – and keyword research will help you with that.
Why have such a Keyword Research in your marketing materials?
There are several reasons. You'll discover how your field is searched, how people ask questions in search engines, you'll uncover different types of keywords that may have some similarities and some differences - in short, you'll find out how people navigate in your field and thus you can make it easier for them to navigate through websites.
If you are serious about online marketing, then keyword research should not be missing in your materials for increasing website traffic from internet search engines.
Thanks to the research, you'll discover which phrases are relevant and beneficial for your website. Subsequently, you can propose the best possible information architecture for the websites or, for example, it can help you with improving your content strategy or building backlinks as part of link building.
Keyword research is a list of keywords, queries, and phrases, to which valuable information useful for your business is added. With this information, you can optimize your website for search engines in various ways - e.g., designing information architecture, revising content strategy, determining the benefit before expanding the business, etc. Furthermore, the analysis helps you understand how your field is searched and whether you cover all possible segments.
The analysis not only helps in SEO (I've also come across the term "SEO analysis," which I don't think is equivalent - SEO analysis should review the overall state of websites from an SEO perspective), but also in PPC (e.g., excluding words for advertising campaigns), mailing (e.g., newsletter - most searched products in the Czech Republic in your field), content marketing - copywriting (SEO texts, SEO articles, ...) and many other areas.
You may have also come across the term KWR, which is not exactly a good abbreviation - Czech and English together. More likely, you would have encountered KWR, which comes from the phrase "Keyword Research".
What is the purpose of the research

You get a list of relevant phrases, queries, and keywords, as people search for you
You find out whether people search according to certain rules/patterns
Materials that you use in various areas of online marketing
You find out which segments you don't cover and thus lose potential visitors
You can discover keywords, for example, that the competition doesn't cover
When designing the information architecture for website creation, or when making adjustments

What will I learn about keywords?
Let's look together at what it's good to find out about queries through keyword research. What you should learn about them, I've divided into several subtopics:

Relevance to your field
Conversion potential of the keyword
Competition/difficulty in making an impact
Segmentation of keywords

Relevance to your field
Are the keywords from the research relevant to your business? Are they beneficial and help you convert a visitor into a customer? Aren't you using keywords that are far from your field and for which you have a high bounce rate? Simply put, you'll find out how important specific keywords are to you and whether you are using them correctly. If you have, for example, an e-shop focused on selling fashion accessories, definitely avoid words like "clothing, garments, ..." Just because you think they are highly searched words (although they are no longer relevant).
Conversion potential of the keyword
Analyze how specific keywords perform in terms of sales. Do the keywords bring sales or just high traffic? From the research, you will learn which KW are beneficial and which you should rather exclude. Your goal is certainly not just to have the highest traffic, but for visitors to fulfill your planned goals - whether it's making a purchase, signing up for a newsletter, or writing a comment. This way, you can increase the conversion ratio and offer people what they really want. After analyzing the queries, you can easily find out how to increase sales.
Competition/difficulty in making an impact
Have you found a segment that you want to optimize? And do you know how difficult it will be? The research will tell you this easily. For example, imagine you have an entry page on the first page of search results at about the 9th position and you decide that you want to start optimizing the given KW - which is highly searched. At the same time, however, you know that you have another entry page with lower search frequency, but it appears on the 5th page and you have almost zero traffic on it. What do you think, will it be easier to optimize the entry page appearing on the first page of search results or the entry page appearing on the 5th page? From experience, I know that it is often worth optimizing pages that are poorly displayed in the results - it takes far less time, you can move the page to, for example, the 2nd page in the results, start driving much higher traffic and thus you can convert visitors into customers sooner (and in the meantime, you manage to optimize other entry pages, than you would have finished optimizing entry pages appearing on the first page). For pages that are well displayed (first page of search results), it is harder to gain better positions in a short time - but it is possible :).
Also, the keyword research over a certain period will tell you, for example, how much a particular keyword brought in sales, what the competition is like in search results, what margin you have on a given segment, what the priority of the business is for selling a particular segment, and many other metrics that you use to determine the difficulty in making an impact.
Segmentation of keywords
As I've already written in the previous point, you'll learn from keywords to which segment they belong - it's kind of a categorization of keywords. From the keyword research, you can filter out whether you are interested in keywords relevant to a certain category, keywords relevant to product pages, informational queries, etc. But that's not all, you'll also find out all the parameters that are searched with it - it could be, for example, color, type of drive, range, power, brand, gender, seasonality, etc. This way, you'll find out which segments are missing on your website - and so the analysis will also help you in designing the website's information architecture - i.e., you'll find out what to use in the main menu, in supporting menus, categories, tags, filters, what entry pages to create, and much more.
If you work on the website considering the research, you won't only gain higher traffic from search engines (or higher positions for current KW), but you will also get a picture of your visitors. You'll understand their searches and can offer them answers, generally speaking, you'll prepare for them and already know what interests them.
The keyword research itself is just one of many pieces to the successful optimization of a website, it's important to also consider on-page factors. If you don't cause problems for search engines in the technical part of SEO, these steps can help you get ahead with search engines. And who wouldn't want to have nice positions on Seznam and Google, or other search engines, right? 🙂
What to Look Out For When Choosing a Keyword Research Provider?
As it often happens, even in the Czech Republic, I encounter marketing agencies or marketing consultants/specialists who create a keyword research and deliver it – unfortunately, it often lacks several factors that help you understand what actually makes sense in reality. Usually, it's just "blindly" researched words from tools – Keyword Planner (Adwords) and Keyword Suggestions (Sklik) – and the associated search volume, sorted from the most searched phrases. In my opinion, these people are more interested in profit, not in standing by you and helping you "kickstart" SEO. If you are a manager or an SEO specialist in a company, the analysis should show you a long-term plan – you need to understand which direction you are heading and why. If you receive an analysis from an agency or freelancer that only contains points for optimization, you won't understand what is more beneficial for you in the long run. In other words, which changes are one-time/short-term, what KPI will the change bring, how is it prioritized, and why,...
So, if you are choosing an agency or a specialist to create a keyword research for you, you need to be cautious about several things – mainly, you must consider what you expect from the research and where and how you want to use it (or the SEO consultant can advise you). Generally, you will probably be interested in:

What segments are not covered, or which ones are not in a "good" state + recommendations on which segments to optimize first and which later, so that you can achieve your set goals as quickly as possible.
What the information architecture should look like – are categories, tags, filters, content pages, etc., correctly designed?
Are we using the right keywords within our content strategy or in naming pages/sections?
Which segments are worth better linking (both internally and through backlinks)?

What Should Not Be Missing in a Quality Research?

Priority – What is currently a priority for me? What can I do later and what should I do now to avoid unnecessary work?
KPI – What will be the result? What will each change bring and how will it manifest? How can I check the change and track further development?
Roadmap – Will I have an overview of all the changes that should be made, and can I record the current progress? Or do I have materials from the provider in which the points are described, showing where to start with optimization and how to continue (closely related to priority)?

Research from the Client's Perspective
Now you will learn what to watch out for when requesting a keyword research. It's important to think about what exactly you require from the research. You can either leave it to the SEO specialist, who will agree on a specific solution with you, or set goals beforehand that you want to achieve through the research.
The research can be done just for a certain area – for content strategy, analyzing a specific product segment/categories, a basis for the SEO specialist – or the keyword research can be broadly focused on your entire segment.
Updated Keyword Research
If you update your keyword research, you will discover new and new topics. If your competition doesn't follow search trends through SEO tools, then you can quickly tap into a segment that will be business-beneficial and yet non-competitive for you. And if you optimize these new segments according to the research (creating new sections/categories/tags/filters, writing articles on current topics, etc.), you can look forward to top positions and an exclusive position in the results 🙂 (of course, it can happen that suddenly the competition starts to push). How to discover new segments and trends, you will learn in a multi-part series on creating a keyword research.
Create or Have KWR Created
If you've read this far, you might decide to create a research. To make your job easier, I have prepared a series of guides for you, where I will take you through several basic steps of creating and explain how to create such a basic keyword research.
Or you can have the research created by me, where I use a more advanced and comprehensive approach, so the output is of very high quality. The described series of guides serves more as an illustration of the research process and as a basic guide.]]></content:encoded>
                
                                    <category><![CDATA[SEO]]></category>
                
                
                                    <enclosure url="https://www.pavelzanek.com/storage/media/29/295e5145-705b-4410-9eea-208537af7cfa/conversions/keyword-research-featured-img-full.jpeg" type="image/jpeg" />
                            </item>
            </channel>
</rss>
