পাতা সাজানো হচ্ছে•••
পাঠকের খেলাঘরছোট্ট বুদ্ধির আসর৬টি টেক প্রশ্ন · প্রতি খেলায় নতুন সেট
ধাঁধা ১ / ৬স্কোর ০ / ৬
আমি ইন্টারনেটের ঠিকানা-বই: নাম থেকে সার্ভারের IP ঠিকানা খুঁজে দিই। আমি কে?

বিজ্ঞাপনের স্থানহেডারের নিচে

Wednesday, October 21, 2026

WordPress Reading Time Shortcode Plugin: বাংলা পোস্টের আনুমানিক পড়ার সময়

WordPress Reading Time Shortcode Plugin: বাংলা পোস্টের আনুমানিক পড়ার সময়

পাঠককে একটি পোস্ট শেষ করতে আনুমানিক সময় জানাতে ছোট shortcode plugin যথেষ্ট। আমরা [reading_time] দিয়ে বর্তমান পোস্ট এবং [reading_time id="123"] দিয়ে নির্দিষ্ট পোস্ট গণনা করব। এটি staging-এ পরীক্ষা করুন, backup রাখুন, এবং মনে রাখুন: বাংলা ও মিশ্র ভাষায় ফলটি estimate, মাপা পাঠ-সময় নয়।

গণনার নিয়ম

Raw content থেকে আগে নিবন্ধিত shortcode সরাব, পরে HTML, script ও style tag বাদ দেব। তারপর Unicode-aware whitespace দিয়ে preg_split('/\s+/u', ...) করব। প্রতি মিনিটে ১৮০ শব্দ ধরে ceil(words / 180), ন্যূনতম ১ মিনিট। punctuation, সংখ্যা, emoji, code ও ছোট শব্দের কারণে বাস্তব সময় আলাদা হতে পারে।

ফাইল বানান

wp-content/plugins/reading-time-bangla/reading-time-bangla.php তৈরি করুন:

<?php
/**
 * Plugin Name: Reading Time Bangla
 * Description: Shows an estimated reading time with a shortcode.
 * Version: 1.0.0
 * Requires at least: 6.0
 * Requires PHP: 7.4
 * License: GPL-2.0-or-later
 */
defined( 'ABSPATH' ) || exit;

File header না থাকলে WordPress plugin চিনবে না। ABSPATH check সরাসরি URL দিয়ে ফাইল চালানো আটকায়।

Shortcode handler

shortcode_atts() optional ID গ্রহণ করে। ID না থাকলে get_the_ID() Loop-এর বর্তমান পোস্ট নির্বাচন করে।

function rt_bangla_shortcode( $atts = array() ) {
    $atts = shortcode_atts(
        array( 'id' => 0 ),
        (array) $atts,
        'reading_time'
    );
    $post_id = absint( $atts['id'] );
    if ( ! $post_id ) {
        $post_id = get_the_ID();
    }
    if ( ! $post_id ) {
        return '';
    }
    $post = get_post( $post_id );
    if ( ! $post instanceof WP_Post ) {
        return '';
    }
    $text = strip_shortcodes( $post->post_content );
    $text = wp_strip_all_tags( $text, true );
    $text = trim( $text );
    if ( '' === $text ) {
        $words = 0;
    } else {
        $parts = preg_split( '/\s+/u', $text, -1, PREG_SPLIT_NO_EMPTY );
        $words = is_array( $parts ) ? count( $parts ) : 0;
    }
    $minutes = max( 1, (int) ceil( $words / 180 ) );
    return esc_html( sprintf( 'পড়তে আনুমানিক %d মিনিট', $minutes ) );
}
add_shortcode( 'reading_time', 'rt_bangla_shortcode' );

কেন ধাপগুলো নিরাপদ

strip_shortcodes() নিবন্ধিত shortcode tag সরায়। wp_strip_all_tags() HTML সরানোর পাশাপাশি script/style-এর content-ও বাদ দেয়। কাঁচা user markup output-এ ফেরত দিচ্ছি না এবং শেষ ফল esc_html()-এ escape করছি। তাই return plain text। Handler-এ ID দিলে সেই পোস্টের content গণনা হয়; Loop-এর বাইরে থাকলে explicit ID দিন। Private content প্রকাশের জন্য এটি ব্যবহার করবেন না; চাইলে পরের সংস্করণে get_post_status() যাচাই যোগ করুন।

ব্যবহার ও পরীক্ষা

Plugin সক্রিয় করে draft বা staging পোস্টে বসান:

[reading_time]
[reading_time id="42"]

খালি content-এ ফল ১ মিনিট থাকবে। বাংলা paragraph, English sentence, heading, link, উদ্ধৃতি এবং অন্য shortcode দিয়ে পরীক্ষা করুন। ১৮০ শব্দ/মিনিট স্থির heuristic; এটি screen-reader সময় বা নিশ্চিত পাঠ-সময় নয়।

রক্ষণাবেক্ষণ

Label অনুবাদযোগ্য করতে __() ও text domain যোগ করা যায়, তবে অনুবাদও escape করুন। বড় সাইটে cache করা সম্ভব, কিন্তু প্রথম সংস্করণে সরলতা ও কম ভুল বেশি গুরুত্বপূর্ণ। Function ও shortcode prefix অনন্য রাখুন, কারণ অন্য plugin একই tag নিবন্ধন করলে আচরণ বদলাতে পারে। Live-এ নেওয়ার আগে PHP lint, staging test, rollback copy এবং backup রাখুন। Core/plugin update-এর পর UTF-8 বাংলা, empty content, invalid ID ও private post আবার পরীক্ষা করুন।

সীমাবদ্ধতা বুঝে ব্যবহার

Unicode regex-এর u flag গুরুত্বপূর্ণ; সেটি ছাড়া UTF-8 text-এ whitespace আচরণ অপ্রত্যাশিত হতে পারে। PREG_SPLIT_NO_EMPTY একাধিক space বা line break থেকে খালি item বাদ দেয়। এটি ভাষাগত tokenization নয়—বাংলা শব্দের সঙ্গে punctuation লেগে থাকলে একটি token-ই ধরা হবে। ফলে এই shortcode analytics বা billing-এর জন্য ব্যবহার করবেন না। এটি পাঠককে দ্রুত একটি ধারণা দেওয়ার UI সহায়ক।

Shortcode-এর নাম prefix করা যায়, কিন্তু এখানে public ব্যবহার সহজ রাখতে reading_time রাখা হয়েছে। একই নামের conflict এড়াতে site-এ সক্রিয় plugin তালিকা দেখুন। Error হলে প্রথমে shortcode spelling, plugin activation, PHP syntax এবং post ID পরীক্ষা করুন। একটি child theme-এ code কপি না করে plugin হিসেবেই রাখুন, যাতে theme বদলালেও reading-time feature থাকে।

Security হিসেবে ID দিয়ে অন্য post পড়ার সম্ভাবনাও ভাবুন। সাধারণ published post-এর জন্য এটি ঠিক, কিন্তু private, pending বা draft content display context-এর বাইরে আনবেন না। প্রয়োজন হলে current_user_can() এবং status check যোগ করুন। Production deployment-এ least privilege, backup, staging এবং rollback ধাপ লিখে রাখলে ছোট plugin-ও রক্ষণাবেক্ষণযোগ্য থাকে।

Testing checklist-এ কয়েকটি edge case রাখুন: ID হিসাবে অক্ষর, শূন্য, deleted post, password-protected post এবং non-post object। absint() ভুল input-কে নিরাপদ integer-এ নামায়, কিন্তু authorization-এর বিকল্প নয়। তাই নির্দিষ্ট ID নিয়ে ফল দেখানোর নীতি সাইটের content visibility-এর সঙ্গে মিলিয়ে নিন। একই সঙ্গে UTF-8 database, Bengali punctuation এবং line break সহ একটি fixture রাখুন।

Output-এ HTML না ফেরানোর সিদ্ধান্ত ইচ্ছাকৃত: theme অনুযায়ী wrapper চাইলে পরে <span> যোগ করে attribute escape করতে হবে। এখন plain text হওয়ায় CSS dependency নেই এবং post editor-এর ভিতরে ব্যবহার সহজ। Version bump ও changelog লিখলে ভবিষ্যতে ১৮০-এর বদলে configurable speed যোগ করাও পরিষ্কার থাকবে।

Official sources

WordPress-এ শূন্য থেকে Minimal Block Theme: theme.json v3, Header ও Footer

WordPress-এ শূন্য থেকে Minimal Block Theme: theme.json v3, Header ও Footer

ব্লক থিম বানাতে জটিল PHP বা বিল্ড টুল আবশ্যক নয়। ফাইল, ব্লক মার্কআপ এবং theme.json দিয়েই একটি ছোট, সম্পাদনাযোগ্য থিম তৈরি করা যায়। এই গাইডের baseline WordPress 6.6+; version 3 schema-কে 6.6-এর সমর্থন হিসেবে ধরা হয়েছে, সর্বশেষ সংস্করণের দাবি হিসেবে নয়। কাজের আগে staging সাইট ও ব্যাকআপ রাখুন।

ফোল্ডার কাঠামো

wp-content/themes/minimal-bangla/-এ নিচের ফাইল রাখুন। templates/index.html থাকাই একটি block theme শনাক্তের ন্যূনতম শর্ত।

minimal-bangla/
├── style.css
├── theme.json
├── templates/index.html
└── parts/{header.html,footer.html}

style.css পরিচয়

সব CSS এখানে না রেখেও থিম তালিকায় পরিচয় দেখাতে header লিখুন:

/*
Theme Name: Minimal Bangla
Author: Your Name
Description: A small learning block theme.
Version: 1.0.0
Text Domain: minimal-bangla
*/

রঙ, spacing ও typography-এর মূল নিয়ন্ত্রণ theme.json-এ রাখলে Site Editor-এ পরিবর্তন করা যায়।

theme.json v3

Official reference অনুযায়ী version 3 WordPress 6.6 বা পরে কাজ করে। নিচে ছোট, পরিচিত সেটিং এবং দুইটি নিবন্ধিত template part আছে:

{
  "$schema": "https://schemas.wp.org/wp/6.6/theme.json",
  "version": 3,
  "settings": {
    "appearanceTools": true,
    "layout": { "contentSize": "720px", "wideSize": "1100px" },
    "color": { "palette": [
      { "slug": "ink", "color": "#202124", "name": "Ink" },
      { "slug": "paper", "color": "#fffdf8", "name": "Paper" },
      { "slug": "accent", "color": "#146c5b", "name": "Accent" }
    ] },
    "typography": { "dropCap": false }
  },
  "styles": {
    "color": { "background": "var(--wp--preset--color--paper)", "text": "var(--wp--preset--color--ink)" },
    "spacing": { "blockGap": "1.4rem" },
    "typography": { "lineHeight": "1.7" }
  },
  "templateParts": [
    { "name": "header", "title": "Header", "area": "header" },
    { "name": "footer", "title": "Footer", "area": "footer" }
  ]
}

$schema editor validation-এ সাহায্য করে। 6.6-এর নিচে version 3 বৈশিষ্ট্য পরীক্ষিত নাও হতে পারে; তাই production-এর আগে target WordPress-এই যাচাই করুন।

Header ও Footer parts

parts/header.html-এ কেবল block markup রাখুন:

<!-- wp:group {"align":"wide","layout":{"type":"flex","justifyContent":"space-between"}} -->
<div class="wp-block-group alignwide">
<!-- wp:site-title /-->
<!-- wp:navigation /-->
</div>
<!-- /wp:group -->

parts/footer.html এমন হতে পারে:

<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:paragraph {"align":"center"} -->
<p class="has-text-align-center">সাদামাটা ও সম্পাদনাযোগ্য।</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:group -->

templates/index.html

Parts নিজে থেকে লোড হয় না; slug-সহ Template Part block লাগবে। Query Loop-এ পোস্টের title, excerpt ও pagination রাখুন:

<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:query {"query":{"perPage":10,"inherit":true}} -->
<div class="wp-block-query">
<!-- wp:post-template -->
<!-- wp:post-title {"isLink":true} /-->
<!-- wp:post-excerpt /-->
<!-- /wp:post-template -->
<!-- wp:query-pagination /-->
</div>
<!-- /wp:query -->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->

সক্রিয় ও যাচাই

Appearance → Themes থেকে থিম সক্রিয় করুন, তারপর Appearance → Editor-এ template খুলুন। Home, মোবাইল প্রস্থ, pagination এবং keyboard navigation পরীক্ষা করুন। Editor-এ পুরনো নকশা দেখালে database-এ saved template আপনার ফাইলকে override করতে পারে। staging-এ saved version সরিয়ে বা পুনরায় কপি করে যাচাই করুন। পরে single.html, page.html ও pattern যোগ করা যাবে। contrast, heading order, backup এবং rollback কপি অবশ্যই পরীক্ষা করুন।

সাধারণ ভুল ও সমাধান

JSON-এ comma বাদ গেলে থিম নাও লোড হতে পারে; তাই একটি JSON validator বা editor schema ব্যবহার করুন। Block comment-এর opening ও closing অংশ জোড়া না থাকলে Editor markup অস্বাভাবিক দেখাতে পারে। Query Loop-এ inherit সত্য রাখলে বর্তমান archive query অনুসরণ করে; home page-এ ফল না এলে Reading Settings, published post এবং permalink পরীক্ষা করুন। Navigation block-এ menu না থাকলে Site Editor থেকে menu নির্বাচন করুন—এটি কোডের ত্রুটি নয়।

একসঙ্গে theme.json ও Editor-এর saved style বদলালে কোনটি কার্যকর হচ্ছে বুঝতে অসুবিধা হয়। প্রথমে ফাইলের baseline রাখুন, তারপর Editor-এ একবারে একটি পরিবর্তন করুন। Git বা অন্তত তারিখ-সহ zip backup রাখলে rollback সহজ। Accessibility-এর জন্য শুধু রঙের উপর নির্ভর করবেন না, focus state এবং heading-এর ক্রম দেখুন। ছোট থিমের উদ্দেশ্য দ্রুত শুরু করা; production design-এ typography, language attribute, responsive spacing এবং error template আলাদা করে যোগ করুন।

আরও একটি বাস্তব পরামর্শ হলো, প্রথমে কেবল এই ন্যূনতম ফাইল দিয়ে থিম চালু করে browser inspector দেখুন। তারপর একবারে একটি color বা spacing পরিবর্তন করুন। এতে theme.json-এর ভুল এবং block markup-এর ভুল আলাদা করে ধরা যায়। Child theme বা plugin-এর style যদি একই selector বদলায়, computed style দেখে উৎস শনাক্ত করুন। কোনো third-party block যোগ করলে তার fallback output ও translation-ও পরীক্ষা করুন।

থিম বিতরণের আগে text domain, license এবং readme যোগ করা ভালো। WordPress 6.6 baseline লিখে রাখুন, কারণ ব্যবহারকারী পুরনো core চালালে version 3 না-ও বুঝতে পারে। Template-এর নাম WordPress hierarchy-র সঙ্গে সামঞ্জস্যপূর্ণ রাখুন এবং database-এ saved customization ফাইলের সঙ্গে আলাদা—এই বিষয়টি changelog-এ জানান।

এই ধাপে পাওয়া কাঠামোটি ইচ্ছাকৃতভাবে ছোট, তাই নতুন বৈশিষ্ট্য যোগ করার আগে baseline কপি করে রাখুন এবং প্রতিটি পরিবর্তন staging-এ যাচাই করুন।

Official sources

Portfolio Custom Post Type Plugin: WordPress-এ Work Archive বানান

Portfolio Custom Post Type Plugin: WordPress-এ Work Archive বানান

Portfolio item যদি সাধারণ post-এর সঙ্গে মিশে যায়, admin-এ কাজ গোছানো থাকে না এবং URL-ও অর্থপূর্ণ হয় না। Custom Post Type (CPT) আলাদা content model দেয়। এই plugin-এ portfolio type, REST/block editor support, archive এবং public URL /work/ বানাব। এটি metadata বা custom fields নয়—সেগুলি পরে আলাদা করে যোগ করা যায়। পরিবর্তনের আগে staging clone ও backup নিন।

Plugin ফাইল

wp-content/plugins/portfolio-content-type/portfolio-content-type.php তৈরি করে নিচের কোড রাখুন। Main plugin file-এই activation hook দেওয়া হয়েছে, যা গুরুত্বপূর্ণ।

<?php
/**
 * Plugin Name: Portfolio Content Type
 * Description: Adds a Portfolio custom post type.
 * Version: 1.0.0
 */
if ( ! defined( 'ABSPATH' ) ) { exit; }

function pct_register_portfolio() {
    register_post_type( 'portfolio', array(
        'labels' => array(
            'name' => __( 'Portfolios', 'pct' ),
            'singular_name' => __( 'Portfolio', 'pct' ),
            'add_new_item' => __( 'Add Portfolio', 'pct' ),
        ),
        'public' => true,
        'show_in_rest' => true,
        'has_archive' => true,
        'rewrite' => array( 'slug' => 'work', 'with_front' => false ),
        'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
        'menu_icon' => 'dashicons-portfolio',
    ) );
}
add_action( 'init', 'pct_register_portfolio' );

function pct_activate() {
    pct_register_portfolio();
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'pct_activate' );

function pct_deactivate() {
    flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'pct_deactivate' );

কেন init এবং show_in_rest?

WordPress-এর init action-এর আগে post type register করা উচিত নয়। তাই callback-টি init-এ যুক্ত করেছি। show_in_rest => true দিলে type REST API-তে আসে এবং block editor ব্যবহার করতে পারে। public ও has_archive front end query এবং archive তৈরি করে। rewrite-এর slug work, তাই একক item-এর URL সাধারণত /work/project-name/ হবে। Post type key ২০ অক্ষরের মধ্যে lowercase রাখা হয়েছে।

Activation flush কেন একবার?

নতুন rewrite structure WordPress-এর permalink rules-এ সঙ্গে সঙ্গে নাও বসতে পারে; ফলে সঠিক post-এ 404 দেখা যায়। Activation routine আগে registration চালিয়ে তারপর flush_rewrite_rules() করে। এই flush প্রত্যেক request-এ করা উচিত নয়—তা অপ্রয়োজনীয় database কাজ তৈরি করে। Deactivation-এ flush রাখা হয়েছে যাতে plugin বন্ধের পর rules পরিষ্কার হয়। Plugin activate করার পর Settings → Permalinks-এ গিয়ে Save করাও manual fallback, কিন্তু code-এর one-time activation যথেষ্ট হওয়া উচিত।

চালানোর ধাপ

Plugins থেকে Portfolio Content Type activate করুন। Admin menu-তে Portfolios আসবে। একটি item-এ title, editor, featured image ও excerpt দিন। তারপর /work/ archive এবং single URL খুলুন। 404 হলে একবার permalink Save করুন এবং permalink structure পরীক্ষা করুন। Block editor না এলে show_in_rest বানানটি ও plugin activation যাচাই করুন।

নিরাপত্তা ও পরের ধাপ

এখানে user input echo করা হয়নি, কারণ WordPress core UI ও templates তা সামলায়। পরে custom template লিখলে title, excerpt, image URL এবং metadata output-এর সময় escape করবেন। taxonomy দরকার হলে register_taxonomy() অথবা register call-এর taxonomies যুক্ত করুন। Capability, custom fields এবং REST exposure বদলালে editorial role ও privacy requirements আগে নির্ধারণ করুন। Uninstall hook-এ data মুছবেন কেবল স্পষ্ট সিদ্ধান্ত থাকলে; deactivation-এর কাজ data delete নয়।

এই ছোট plugin production-ready architecture-এর ভিত্তি, সম্পূর্ণ portfolio design নয়। CSS, archive template এবং structured data আপনার brand ও accessibility পরীক্ষা অনুযায়ী যোগ করুন।

ডেটা মডেল নিয়ে ভাবুন

CPT-এর নাম ভবিষ্যতে বদলানো কঠিন, তাই singular key ছোট ও স্থির রাখুন। Label মানুষের জন্য, key code-এর জন্য—দুটিকে আলাদা ভাবুন। Archive লাগবে না হলে has_archive false করতে পারেন; কিন্তু portfolio collection-এর ক্ষেত্রে archive useful। with_front false দিলে site-এর blog prefix থাকলেও work URL পরিষ্কার থাকে।

REST exposure মানে editor integration এবং API response-এর সুবিধা; এটি private data প্রকাশের অনুমতি নয়। public content-এর ক্ষেত্রেই ব্যবহার করুন। নির্দিষ্ট field REST-এ দিলে permission ও sanitization callback ঠিক করুন। Featured image ব্যবহার করলে theme বা archive template-এ image-এর alt text সঠিকভাবে রক্ষিত হচ্ছে কি না পরীক্ষা করুন।

Rewrite flush ব্যয়বহুল হওয়ায় activation এবং deactivation-এ সীমাবদ্ধ রাখুন। Code update-এ নতুন slug আনলে user-কে deactivate/activate বা permalinks save করার নির্দেশ দিতে পারেন। Activation failure হলে PHP syntax, file path এবং plugin header যাচাই করুন। বাস্তব site-এ migration-এর আগে URL redirect পরিকল্পনা করুন, যাতে পুরোনো portfolio link হারিয়ে না যায়।

ছোট কিন্তু জরুরি যাচাই

কোড বসানোর পরে শুধু editor-এ সবুজ দেখালেই শেষ নয়। আলাদা browser-এ logged-out অবস্থায় page খুলুন, keyboard দিয়ে link ও control চালান, এবং mobile width-এ horizontal scroll হচ্ছে কি না দেখুন। PHP ও WordPress version-এর compatibility নোট করুন। staging-এ error log দেখে warning থাকলে সমাধান করুন; live সাইটে অযথা debug output দেখাবেন না। Backup ফেরত আনার পদ্ধতিও আগে পরীক্ষা করে রাখুন। কোনও third-party plugin একই hook বা class ব্যবহার করছে কি না দেখলে prefix বদলান। ছোট পরিবর্তন একবারে deploy করলে সমস্যা হলে কোন অংশ rollback করতে হবে তা স্পষ্ট থাকে। এই নিয়মগুলি theme, shortcode এবং CPT—তিন ক্ষেত্রেই প্রযোজ্য।

নোট লিখে রাখুন কোন file কোথায় রাখা হয়েছে এবং কোন shortcode বা URL পরীক্ষা করা হয়েছে। এতে ভবিষ্যতের update-এ ভুল কমে এবং অন্য developer দ্রুত দায়িত্ব নিতে পারেন। এই অভ্যাসটি রাখুন।

আরও পড়ুন

সতর্কতা: লাইভ সাইটে বদলানোর আগে staging কপি, পূর্ণ backup এবং rollback পরিকল্পনা রাখুন। কোডটি নিজের WordPress/PHP সংস্করণে পরীক্ষা করুন।

নিরাপদ Accessible Notice Box-এর জন্য Custom WordPress Shortcode Plugin

নিরাপদ Accessible Notice Box-এর জন্য Custom WordPress Shortcode Plugin

বারবার সতর্কতা, টিপস বা সাফল্যের বার্তা লিখতে HTML কপি-পেস্ট করা বিরক্তিকর। একটি ছোট shortcode plugin এই কাজকে সম্পাদকের জন্য সহজ করে, আবার theme বদলালেও কাজটি রেখে দেয়। এই উদাহরণে [bns_notice] tag, তিনটি সীমিত type এবং accessible aside ব্যবহার করব। শুরুতেই staging-এ plugin চালান; production-এ নেওয়ার আগে backup রাখুন।

কেন plugin, theme নয়?

Shortcode হলো content-এর ছোট placeholder, যা render-এর সময় callback-এ যায়। Theme-এর functions.php-তে রাখলে theme বদলালে হারাতে পারে; plugin-এ রাখলে content portability ভালো থাকে। Tag-এ নিজের prefix ব্যবহার করুন, কারণ একই নামের shortcode হলে পরে load হওয়া callback আগেরটিকে override করতে পারে।

ফাইল ও কোড

wp-content/plugins/bengali-notice-shortcode/bengali-notice-shortcode.php বানিয়ে এই কোড বসান:

<?php
/**
 * Plugin Name: Bengali Notice Shortcode
 * Description: Accessible notice box shortcode.
 * Version: 1.0.0
 */
if ( ! defined( 'ABSPATH' ) ) { exit; }

function bns_notice_shortcode( $atts, $content = null ) {
    $atts = shortcode_atts(
        array( 'type' => 'info', 'title' => '' ),
        $atts,
        'bns_notice'
    );
    $allowed = array( 'info', 'success', 'warning' );
    $type = in_array( $atts['type'], $allowed, true ) ? $atts['type'] : 'info';
    $title = sanitize_text_field( $atts['title'] );
    $body  = wp_kses_post( do_shortcode( $content ?? '' ) );
    $label = $title ? '<strong class="bns-title">' . esc_html( $title ) . '</strong>' : '';
    return '<aside class="bns-notice bns-' . esc_attr( $type ) . '" role="status">' . $label . '<div>' . $body . '</div></aside>';
}
add_shortcode( 'bns_notice', 'bns_notice_shortcode' );

কোডটি কীভাবে নিরাপদ?

shortcode_atts() শুধু অনুমোদিত type ও title রাখে এবং default পূরণ করে। type-কে allow-list দিয়ে মিলিয়েছি; অজানা value হলে info হবে। title plain text, তাই sanitize_text_field() দিয়ে পরিষ্কার করে output-এ esc_html() করেছি। class attribute-এ esc_attr() আছে। ভেতরের content-এ সাধারণ formatting দরকার বলে wp_kses_post() ব্যবহার করেছি—এটি arbitrary script ঢুকতে দেয় না। Shortcode callback-এ echo নয়, string return করা উচিত।

ব্যবহার

[bns_notice type="warning" title="ব্যাকআপ নিন"]লাইভ সাইটে পরিবর্তনের আগে staging পরীক্ষা করুন।[/bns_notice]

[bns_notice type="success" title="সম্পন্ন"]ফাইলটি আপলোড হয়েছে।[/bns_notice]

[bns_notice]শুধু তথ্যের বার্তা।[/bns_notice]

Plugin activate করে একটি post-এ shortcode দিন। Output দেখে keyboard focus, contrast এবং screen reader-এ অর্থপূর্ণ ঘোষণা হচ্ছে কি না পরীক্ষা করুন। role="status" সাধারণ status বার্তার জন্য উপযোগী; জরুরি বিপদ হলে আলাদা আচরণ দরকার, তাই নির্বিচারে alert ব্যবহার করবেন না। CSS না থাকলেও semantic aside পাঠযোগ্য থাকবে। চাইলে plugin-এ enqueue করা ছোট stylesheet যোগ করুন—inline style দিয়ে content ভারী করবেন না।

সীমা ও রক্ষণাবেক্ষণ

এই shortcode title-এ markup ইচ্ছাকৃতভাবে নিষিদ্ধ। body-তে allowed HTML রাখা হয়েছে, তবুও untrusted shortcode nesting বা third-party filter থাকলে staging-এ পরীক্ষা জরুরি। Function prefix করা হয়েছে যাতে global namespace সংঘর্ষ কমে। ভবিষ্যতে নতুন type যোগ করলে allow-list, CSS এবং documentation একসঙ্গে বদলান।

সম্পাদকের জন্য ছোট নিয়ম

একটি notice-এ একটাই উদ্দেশ্য রাখুন। title সংক্ষিপ্ত, body-তে সরাসরি নির্দেশনা এবং প্রয়োজন হলে একটি descriptive link দিন। একই post-এ অনেক nested notice দিলে screen reader-এর reading flow ভারী হতে পারে। তাই editorial guideline-এ type-এর অর্থ লিখে দিন: info সাধারণ তথ্য, success সম্পন্ন কাজ, warning সতর্কতা।

CSS যোগ করার সময় শুধু রঙের উপর নির্ভর করবেন না; border, icon-এর accessible label বা heading-ও ব্যবহার করুন। contrast checker দিয়ে foreground ও background পরীক্ষা করুন। HTML output পরিবর্তন করলে view-source এবং keyboard navigation দুটোই যাচাই করুন। Shortcode content-এ user-generated text থাকলে allowed markup সীমিত রাখাই নিরাপদ।

Plugin update করার আগে staging-এ পুরোনো post render হচ্ছে কি না দেখুন। shortcode tag rename করলে পুরোনো content ভেঙে যাবে, তাই দরকার হলে পুরোনো tag-এর compatibility alias রাখুন। Function name-এ prefix এবং unique CSS class ব্যবহার করলে অন্য plugin-এর সঙ্গে সংঘর্ষের সম্ভাবনা কমে।

ছোট কিন্তু জরুরি যাচাই

কোড বসানোর পরে শুধু editor-এ সবুজ দেখালেই শেষ নয়। আলাদা browser-এ logged-out অবস্থায় page খুলুন, keyboard দিয়ে link ও control চালান, এবং mobile width-এ horizontal scroll হচ্ছে কি না দেখুন। PHP ও WordPress version-এর compatibility নোট করুন। staging-এ error log দেখে warning থাকলে সমাধান করুন; live সাইটে অযথা debug output দেখাবেন না। Backup ফেরত আনার পদ্ধতিও আগে পরীক্ষা করে রাখুন। কোনও third-party plugin একই hook বা class ব্যবহার করছে কি না দেখলে prefix বদলান। ছোট পরিবর্তন একবারে deploy করলে সমস্যা হলে কোন অংশ rollback করতে হবে তা স্পষ্ট থাকে। এই নিয়মগুলি theme, shortcode এবং CPT—তিন ক্ষেত্রেই প্রযোজ্য।

নোট লিখে রাখুন কোন file কোথায় রাখা হয়েছে এবং কোন shortcode বা URL পরীক্ষা করা হয়েছে। এতে ভবিষ্যতের update-এ ভুল কমে এবং অন্য developer দ্রুত দায়িত্ব নিতে পারেন। এই অভ্যাসটি রাখুন।

আরও পড়ুন

সতর্কতা: লাইভ সাইটে বদলানোর আগে staging কপি, পূর্ণ backup এবং rollback পরিকল্পনা রাখুন। কোডটি নিজের WordPress/PHP সংস্করণে পরীক্ষা করুন।

শূন্য থেকে Minimal Classic WordPress Theme বানানোর সহজ গাইড

শূন্য থেকে Minimal Classic WordPress Theme বানানোর সহজ গাইড

নিজের হাতে একটি classic WordPress theme বানানো শেখার সবচেয়ে ভালো উপায় হলো ছোট রাখা। এখানে আমরা block theme নয়, template-ভিত্তিক একটি ন্যূনতম theme বানাব। লক্ষ্য সুন্দর ডিজাইন নয়; বরং WordPress কীভাবে header, loop, asset এবং footer জোড়া দেয় তা বোঝা। কাজের আগে staging সাইটে পরীক্ষা করুন এবং বর্তমান theme-এর backup রাখুন।

ফোল্ডার তৈরি

wp-content/themes/shobuj-minimal/ নামে ফোল্ডার বানান। Classic theme চিনতে WordPress-এর জন্য style.css দরকার; শিরোনামের comment-এ অন্তত Theme Name থাকতে হবে। পাশাপাশি functions.php, index.php, header.php এবং footer.php রাখব।

style.css: পরিচয় এবং নকশা

ফাইলের প্রথম comment-এ theme metadata দিন। নিচের CSS ইচ্ছাকৃতভাবে সাধারণ; পরে নিজের রং ও layout যোগ করতে পারবেন।

/**
 * Theme Name: Shobuj Minimal
 * Description: A tiny classic theme for learning.
 * Version: 1.0
 * Author: Your Name
 * Text Domain: shobuj-minimal
 */

body { margin: 0; font: 16px/1.6 system-ui, sans-serif; color: #222; }
.site-header, .site-footer { padding: 1rem; background: #173b2a; color: #fff; }
.site-main { max-width: 760px; margin: 2rem auto; padding: 0 1rem; }
a { color: #075e45; }

functions.php: asset ও feature

CSS সরাসরি template-এ বসানোর বদলে enqueue করা WordPress-এর স্বাভাবিক পদ্ধতি। after_setup_theme-এ title tag, featured image এবং menu support যোগ করছি।

<?php
/** Load the theme stylesheet. */
function shobuj_minimal_assets() {
    wp_enqueue_style(
        'shobuj-minimal',
        get_stylesheet_uri(),
        array(),
        wp_get_theme()->get('Version')
    );
}
add_action('wp_enqueue_scripts', 'shobuj_minimal_assets');

function shobuj_minimal_setup() {
    add_theme_support('title-tag');
    add_theme_support('post-thumbnails');
    register_nav_menus(array('primary' => __('Primary Menu', 'shobuj-minimal')));
}
add_action('after_setup_theme', 'shobuj_minimal_setup');

header.php: hook ভুলবেন না

language_attributes() ও charset accessibility এবং আন্তর্জাতিকীকরণে সহায়ক। wp_head() closing head-এর আগে, আর opening body-র পরেই wp_body_open() রাখুন। Plugin-এর scripts, styles, analytics বা accessibility tooling এই hook ব্যবহার করতে পারে।

<!doctype html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<header class="site-header"><a href="<?php echo esc_url(home_url('/')); ?>"><?php bloginfo('name'); ?></a></header>

index.php: নিরাপদ Loop

Loop-এ have_posts() দিয়ে ফল আছে কি না দেখা হয়, তারপর the_post() global post প্রস্তুত করে। শিরোনামের URL-এ esc_url(), তারিখে esc_html() ব্যবহার করেছি। Content দেখানোর জন্য the_excerpt() ব্যবহার করলে WordPress-এর তৈরি excerpt যথাযথ থাকে।

<?php get_header(); ?>

<main id="primary" class="site-main">
    <?php if (have_posts()) : ?>
        <?php while (have_posts()) : the_post(); ?>
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <h2><a href="<?php echo esc_url(get_permalink()); ?>"><?php the_title(); ?></a></h2>
                <p><?php echo esc_html(get_the_date()); ?></p>
                <?php the_excerpt(); ?>
            </article>
        <?php endwhile; ?>
        <?php the_posts_pagination(); ?>
    <?php else : ?>
        <p><?php esc_html_e('কোনও লেখা পাওয়া যায়নি।', 'shobuj-minimal'); ?></p>
    <?php endif; ?>
</main>

<?php get_footer(); ?>

footer.php এবং পরীক্ষা

footer-এর closing body-এর ঠিক আগে wp_footer() থাকা আবশ্যক।

<footer class="site-footer"><p><?php echo esc_html(get_bloginfo('name')); ?></p></footer>
<?php wp_footer(); ?>
</body>
</html>

এখন Appearance থেকে theme activate করুন। Home page, কোনও post, search, empty result এবং mobile width দেখুন। Menu না দেখালেও প্রথম ধাপে সমস্যা নয়; পরের ধাপে wp_nav_menu() বসাতে পারবেন। PHP syntax error হলে staging-এর error log দেখুন, live site-এ অন্ধভাবে paste করবেন না।

দৈনন্দিন workflow

প্রথমে requirements লিখে নিন: site title কোথায়, navigation কতটি, post excerpt কতটা এবং typography কী হবে। তারপর HTML structure স্থির করে CSS দিন। Template-এ business logic না রেখে ছোট helper functions রাখলে theme maintain করা সহজ হয়। WordPress-এর template hierarchy পরে শিখলে home, single এবং archive আলাদা ফাইল করতে পারবেন; শুরুতে index.php fallback হিসেবে যথেষ্ট।

Loop-এর ভেতরে বড় raw HTML বা user-provided attribute সরাসরি বসাবেন না। URL, class, text এবং HTML-এর জন্য প্রসঙ্গভেদে আলাদা escaping দরকার। এই অভ্যাস ভবিষ্যতের theme-এ নিরাপত্তা সমস্যা কমায়। Accessibility-এর জন্য heading ক্রম ঠিক রাখুন, link text অর্থপূর্ণ করুন এবং keyboard-এ menu চালানো যায় কি না দেখুন।

শেষে একটি ছোট checklist রাখুন: theme activate, front page, search, pagination, 404, logged-out visitor এবং mobile viewport। PHP warning দেখা গেলে debug log-এ কারণ খুঁজুন, কিন্তু debug display live-এ চালু রাখবেন না। এই minimal theme ইচ্ছাকৃতভাবে comments, sidebar বা customizer যোগ করেনি—সেগুলি আলাদা feature হিসেবে একবারে একটিই যোগ করুন।

ছোট কিন্তু জরুরি যাচাই

কোড বসানোর পরে শুধু editor-এ সবুজ দেখালেই শেষ নয়। আলাদা browser-এ logged-out অবস্থায় page খুলুন, keyboard দিয়ে link ও control চালান, এবং mobile width-এ horizontal scroll হচ্ছে কি না দেখুন। PHP ও WordPress version-এর compatibility নোট করুন। staging-এ error log দেখে warning থাকলে সমাধান করুন; live সাইটে অযথা debug output দেখাবেন না। Backup ফেরত আনার পদ্ধতিও আগে পরীক্ষা করে রাখুন। কোনও third-party plugin একই hook বা class ব্যবহার করছে কি না দেখলে prefix বদলান। ছোট পরিবর্তন একবারে deploy করলে সমস্যা হলে কোন অংশ rollback করতে হবে তা স্পষ্ট থাকে। এই নিয়মগুলি theme, shortcode এবং CPT—তিন ক্ষেত্রেই প্রযোজ্য।

নোট লিখে রাখুন কোন file কোথায় রাখা হয়েছে এবং কোন shortcode বা URL পরীক্ষা করা হয়েছে। এতে ভবিষ্যতের update-এ ভুল কমে এবং অন্য developer দ্রুত দায়িত্ব নিতে পারেন। এই অভ্যাসটি রাখুন।

আরও পড়ুন

সতর্কতা: লাইভ সাইটে বদলানোর আগে staging কপি, পূর্ণ backup এবং rollback পরিকল্পনা রাখুন। কোডটি নিজের WordPress/PHP সংস্করণে পরীক্ষা করুন।

বিজ্ঞাপনের স্থানপোস্ট ১
বিজ্ঞাপনের স্থানপোস্ট ২
বিজ্ঞাপনের স্থানপোস্ট ৩
About Me
পরিচয়
নাম

নাজমুল ইসলাম

ভূমিকা

Tech Specialist

আরও পরিচিতি
শিক্ষা / পড়াশোনার বিষয়
HSC
কাজ / প্রযুক্তির ক্ষেত্র / দক্ষতা
শহর / জেলা
শখ / আগ্রহ
ব্লগের বিষয় / পাঠকদের জন্য সংক্ষিপ্ত পরিচিতি
ব্যক্তিগত লেখা, ছোট গল্প ও প্রযুক্তি ভাবনা নিয়ে লিখি।
পাবলিক ওয়েবসাইট / সোশ্যাল লিংক
শেষের পরিচিতি
নাজমুল ইসলাম · Tech Specialist

লেখার আর্কাইভ

মাস অনুযায়ী পুরোনো লেখাগুলো খুঁজে নিন।