{"id":113,"date":"2026-01-30T10:35:47","date_gmt":"2026-01-30T02:35:47","guid":{"rendered":"http:\/\/47.100.165.17\/wordpress\/?p=113"},"modified":"2026-02-01T19:39:15","modified_gmt":"2026-02-01T11:39:15","slug":"%e6%b5%8b%e8%af%952","status":"publish","type":"post","link":"https:\/\/yunyanglib.cn\/?p=113","title":{"rendered":"\u3010\u7f51\u7ad9\u5efa\u8bbe\u3011\u201d\u70ed\u529b\u56fe\u201c\u529f\u80fd\u5b9e\u73b0"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u5b9e\u73b0\u4e0b\u9762\u8fd9\u79cd\u7c7b\u4f3c GitHub \u8d21\u732e\u70ed\u529b\u56fe\u7684\u300c\u521b\u4f5c\u6307\u6570\u65e5\u5386\u300d<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"242\" src=\"http:\/\/47.100.165.17\/wordpress\/wp-content\/uploads\/2026\/01\/Snipaste_2026-01-30_14-29-49-1024x242.png\" alt=\"\" class=\"wp-image-148\" srcset=\"https:\/\/yunyanglib.cn\/wp-content\/uploads\/2026\/01\/Snipaste_2026-01-30_14-29-49-1024x242.png 1024w, https:\/\/yunyanglib.cn\/wp-content\/uploads\/2026\/01\/Snipaste_2026-01-30_14-29-49-300x71.png 300w, https:\/\/yunyanglib.cn\/wp-content\/uploads\/2026\/01\/Snipaste_2026-01-30_14-29-49-768x181.png 768w, https:\/\/yunyanglib.cn\/wp-content\/uploads\/2026\/01\/Snipaste_2026-01-30_14-29-49.webp 1276w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">\u4fee\u6539\u5b50\u4e3b\u9898<code>functions.php<\/code>\u4ee3\u7801<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\/\/ 1. \u6570\u636e\u83b7\u53d6\uff1a\u5f53\u524d\u81ea\u7136\u5e74\u6587\u7ae0\nfunction contribution_heatmap_get_data() {\n    \/\/ \u7edf\u4e00\u4f7f\u7528WordPress\u65f6\u533a\u83b7\u53d6\u5e74\u4efd\n    $current_year = wp_date('Y');\n    \n    \/\/ \u4f18\u5316WP_Query\u53c2\u6570\uff1a\u89e3\u51b3\u67e5\u8be2\u9057\u6f0f+\u8fb9\u754c\u6a21\u7cca\u95ee\u9898\n    $args = array(\n        'post_type' =&gt; 'post',\n        'post_status' =&gt; 'publish',\n        'posts_per_page' =&gt; -1,\n        'fields' =&gt; 'post_date',\n        'no_found_rows' =&gt; true,\n        'ignore_sticky_posts' =&gt; true,\n        'date_query' =&gt; array(\n            array(\n                'column' =&gt; 'post_date',\n                'after' =&gt; $current_year . '-01-01 00:00:00',\n                'before' =&gt; $current_year . '-12-31 23:59:59',\n                'inclusive' =&gt; true,\n            ),\n        ),\n    );\n    \n    \/\/ \u6267\u884c\u67e5\u8be2\n    $query = new WP_Query($args);\n    $contribution_data = array();\n\n    \/\/ \u65e5\u5fd7\uff1a\u6253\u5370\u67e5\u8be2\u603b\u6570\n    error_log('=== \u70ed\u529b\u56fe\u7edf\u8ba1\u5f00\u59cb ===');\n    error_log('\u5f53\u524d\u7edf\u8ba1\u5e74\u4efd\uff1a' . $current_year);\n    error_log('\u672c\u6b21\u67e5\u8be2\u5230\u6587\u7ae0\u603b\u6570\uff1a' . count($query-&gt;posts));\n\n    foreach ($query-&gt;posts as $post) {\n        \/\/ 1. \u539f\u59cb\u65e5\u671f\uff08\u6570\u636e\u5e93\u91cc\u7684UTC\u65f6\u533adatetime\u5b57\u7b26\u4e32\uff09\n        $raw_post_date = $post-&gt;post_date;\n        \n        \/\/ 2. \u5173\u952e\uff1a\u76f4\u63a5\u63d0\u53d6\u524d10\u4f4d\uff08YYYY-MM-DD\uff09\uff0c\u8df3\u8fc7\u65f6\u533a\u8f6c\u6362\uff0c\u907f\u514d\u8de8\u5929\n        if (strlen($raw_post_date) &lt; 10) {\n            error_log('\u8b66\u544a\uff1a\u539f\u59cb\u65e5\u671f ' . $raw_post_date . ' \u683c\u5f0f\u5f02\u5e38\uff0c\u5df2\u8df3\u8fc7');\n            continue;\n        }\n        $formatted_date = substr($raw_post_date, 0, 10);\n        \n        \/\/ 3. \u65e5\u5fd7\uff1a\u6253\u5370\u539f\u59cb\u65e5\u671f\u3001\u63d0\u53d6\u540e\u7684\u7edf\u8ba1\u65e5\u671f\uff08\u65b9\u4fbf\u9a8c\u8bc1\uff09\n        error_log('\u539f\u59cbUTC\u65e5\u671f\uff1a' . $raw_post_date . ' | \u7edf\u8ba1\u65e5\u671f\uff1a' . $formatted_date);\n\n        \/\/ 4. \u7edf\u8ba1\u6bcf\u65e5\u6587\u7ae0\u6570\uff08\u65e0\u6570\u91cf\u4e0a\u9650\uff09\n        if (isset($contribution_data&#091;$formatted_date])) {\n            $contribution_data&#091;$formatted_date]++;\n        } else {\n            $contribution_data&#091;$formatted_date] = 1;\n        }\n    }\n\n    \/\/ \u65e5\u5fd7\uff1a\u6253\u5370\u6700\u7ec8\u7edf\u8ba1\u7ed3\u679c\n    error_log('\u6700\u7ec8\u65e5\u671f\u7edf\u8ba1\u7ed3\u679c\uff1a' . print_r($contribution_data, true));\n    error_log('=== \u70ed\u529b\u56fe\u7edf\u8ba1\u7ed3\u675f ===' . \"\\n\");\n\n    wp_reset_postdata();\n    return $contribution_data;\n}\n\n\/\/ 2. \u77ed\u4ee3\u7801\uff1a\u65b0\u589e\u9f20\u6807\u60ac\u6d6etooltip\uff0c\u533a\u5206\u8fc7\u53bb\/\u672a\u6765\u65e5\u671f\nfunction contribution_heatmap_shortcode() {\n    ob_start();\n    $contribution_data = contribution_heatmap_get_data();\n    $json_data = json_encode($contribution_data);\n    $current_year = date('Y');\n    ?&gt;\n\n    &lt;div id=\"contribution-wrapper\" style=\"width: 800px; margin: 20px 0;\"&gt;\n        &lt;!-- \u53f3\u4e0a\u89d24\u7ea7\u8272\u5757\u56fe\u4f8b --&gt;\n        &lt;div id=\"heatmap-legend\" style=\"display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-bottom: 10px;\"&gt;\n            &lt;span style=\"font-size: 0.9rem; color: #666;\"&gt;\u4e0d\u6d3b\u8dc3&lt;\/span&gt;\n            &lt;div style=\"width: 20px; height: 20px; background: #ffffff; border: 1px solid #e0e0e0;\"&gt;&lt;\/div&gt;\n            &lt;div style=\"width: 20px; height: 20px; background: #c8e6c9; border: 1px solid #e0e0e0;\"&gt;&lt;\/div&gt;\n            &lt;div style=\"width: 20px; height: 20px; background: #66bb6a; border: 1px solid #e0e0e0;\"&gt;&lt;\/div&gt;\n            &lt;div style=\"width: 20px; height: 20px; background: #2e7d32; border: 1px solid #e0e0e0;\"&gt;&lt;\/div&gt;\n            &lt;span style=\"font-size: 0.9rem; color: #666;\"&gt;\u6d3b\u8dc3&lt;\/span&gt;\n        &lt;\/div&gt;\n\n        &lt;!-- \u70ed\u529b\u56fe\u5bb9\u5668 --&gt;\n        &lt;div id=\"contribution-heatmap\" style=\"width: 100%; height: 250px; padding: 20px; border: 1px solid #ddd;\"&gt;\n            &lt;div id=\"full-calendar\" style=\"width: 100%; height: 100%;\"&gt;&lt;\/div&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n\n    &lt;script src=\"https:\/\/cdn.bootcdn.net\/ajax\/libs\/d3\/7.8.5\/d3.min.js\"&gt;&lt;\/script&gt;\n    &lt;script&gt;\n    window.onload = function() {\n        if (!d3) {\n            document.getElementById(\"contribution-heatmap\").innerHTML = \"D3\u52a0\u8f7d\u5931\u8d25\";\n            return;\n        }\n\n        const contributionData = &lt;?php echo $json_data; ?&gt;;\n        const startDate = new Date(\"&lt;?php echo $current_year; ?&gt;\", 0, 1);\n        const endDate = new Date(\"&lt;?php echo $current_year; ?&gt;\", 11, 31);\n        const today = new Date(); \/\/ \u83b7\u53d6\u5f53\u524d\u65e5\u671f\uff08\u7528\u4e8e\u533a\u5206\u8fc7\u53bb\/\u672a\u6765\uff09\n        today.setHours(0, 0, 0, 0); \/\/ \u91cd\u7f6e\u65f6\u95f4\u4e3a0\u70b9\uff0c\u907f\u514d\u65f6\u5206\u79d2\u5e72\u6270\u65e5\u671f\u5224\u65ad\n        const dateRange = d3.timeDays(startDate, endDate);\n        const cellSize = 14;\n        const margin = { top: 20, right: 10, bottom: 30, left: 10 };\n\n        \/\/ ******** \u65b0\u589e1\uff1a\u521b\u5efatooltip\u5143\u7d20\uff08\u9ed8\u8ba4\u9690\u85cf\uff09 ********\n        const tooltip = d3.select(\"body\").append(\"div\")\n            .attr(\"class\", \"heatmap-tooltip\")\n            .style(\"position\", \"absolute\")\n            .style(\"background-color\", \"#ffffff\")\n            .style(\"border\", \"1px solid #e0e0e0\")\n            .style(\"border-radius\", \"4px\")\n            .style(\"padding\", \"6px 10px\")\n            .style(\"font-size\", \"0.9rem\")\n            .style(\"box-shadow\", \"0 2px 5px rgba(0, 0, 0, 0.1)\")\n            .style(\"opacity\", 0) \/\/ \u9ed8\u8ba4\u900f\u660e\u9690\u85cf\n            .style(\"pointer-events\", \"none\") \/\/ \u4e0d\u963b\u6321\u9f20\u6807\u4e8b\u4ef6\n            .style(\"z-index\", \"9999\"); \/\/ \u786e\u4fdd\u5728\u6700\u4e0a\u5c42\n\n        \/\/ \u521b\u5efaSVG\u5bb9\u5668\n        const svg = d3.select(\"#full-calendar\")\n            .append(\"svg\")\n            .attr(\"width\", \"100%\")\n            .attr(\"height\", \"100%\")\n            .append(\"g\")\n            .attr(\"transform\", `translate(${margin.left}, ${margin.top})`);\n\n        \/\/ ******** \u65b0\u589e2\uff1a\u65e5\u671f\u683c\u5f0f\u5316\u51fd\u6570\uff082026-01-26 Mon\uff09 ********\n        const dateFormatter = d3.timeFormat(\"%Y-%m-%d %a\"); \/\/ %Y=\u5e74, %m=\u6708, %d=\u65e5, %a=\u661f\u671f\u7f29\u5199\uff08Mon\/Tue\u7b49\uff09\n\n        \/\/ \u70ed\u529b\u56fe\u989c\u8272\uff1a\u4e0e4\u7ea7\u56fe\u4f8b\u5bf9\u5e94\n        const cells = svg.selectAll(\".cell\")\n            .data(dateRange)\n            .enter().append(\"rect\")\n            .attr(\"class\", \"cell\")\n            .attr(\"width\", cellSize - 1)\n            .attr(\"height\", cellSize - 1)\n            .attr(\"x\", d =&gt; d3.timeWeek.count(d3.timeYear(d), d) * cellSize)\n            .attr(\"y\", d =&gt; d3.timeFormat(\"%w\")(d) * cellSize)\n            .attr(\"fill\", d =&gt; {\n                const dateStr = d3.timeFormat(\"%Y-%m-%d\")(d);\n                if (contributionData&#091;dateStr] &gt;= 3) return \"#2e7d32\"; \/\/ \u7b49\u7ea74\uff08\u6d3b\u8dc3\uff09\n                if (contributionData&#091;dateStr] &gt;= 2) return \"#66bb6a\"; \/\/ \u7b49\u7ea73\n                if (contributionData&#091;dateStr] &gt;= 1) return \"#c8e6c9\"; \/\/ \u7b49\u7ea72\n                return \"#ffffff\"; \/\/ \u7b49\u7ea71\uff08\u4e0d\u6d3b\u8dc3\uff09\n            })\n            .attr(\"stroke\", \"#f0f0f0\");\n\n        \/\/ ******** \u65b0\u589e3\uff1a\u9f20\u6807\u60ac\u6d6e\u4e8b\u4ef6\uff08\u533a\u5206\u8fc7\u53bb\/\u672a\u6765\u65e5\u671f\uff09 ********\n        cells\n            \/\/ \u9f20\u6807\u79fb\u5165\uff1a\u663e\u793atooltip\n            .on(\"mouseover\", function(event, d) {\n                \/\/ 1. \u683c\u5f0f\u5316\u65e5\u671f\u4e3a\u300c2026-01-26 Mon\u300d\u683c\u5f0f\n                const formattedDate = dateFormatter(d);\n                \/\/ 2. \u91cd\u7f6e\u5f53\u524d\u65e5\u671f\u7684\u65f6\u5206\u79d2\uff08\u907f\u514d\u65f6\u5206\u79d2\u5e72\u6270\u5224\u65ad\uff09\n                const cellDate = new Date(d);\n                cellDate.setHours(0, 0, 0, 0);\n\n                \/\/ 3. \u533a\u5206\u300c\u8fc7\u53bb\/\u5f53\u524d\u65e5\u671f\u300d\u548c\u300c\u672a\u6765\u65e5\u671f\u300d\n                let tooltipContent = \"\";\n                if (cellDate &lt;= today) {\n                    \/\/ \u8fc7\u53bb\/\u5f53\u524d\u65e5\u671f\uff1a\u663e\u793a\u300c\u65e5\u671f + \u6587\u7ae0\u6570\u300d\n                    const dateStr = d3.timeFormat(\"%Y-%m-%d\")(d);\n                    const articleCount = contributionData&#091;dateStr] || 0;\n                    tooltipContent = `${formattedDate}&lt;br&gt;\u521b\u4f5c\u6587\u7ae0\uff1a${articleCount} \u7bc7`;\n                } else {\n                    \/\/ \u672a\u6765\u65e5\u671f\uff1a\u53ea\u663e\u793a\u300c\u65e5\u671f\u300d\n                    tooltipContent = formattedDate;\n                }\n\n                \/\/ 4. \u663e\u793atooltip\u5e76\u8c03\u6574\u4f4d\u7f6e\uff08\u8ddf\u968f\u9f20\u6807\uff09\n                tooltip.html(tooltipContent)\n                    .style(\"left\", (event.pageX + 10) + \"px\") \/\/ \u9f20\u6807\u53f3\u4fa710px\n                    .style(\"top\", (event.pageY - 20) + \"px\") \/\/ \u9f20\u6807\u4e0a\u65b920px\n                    .transition() \/\/ \u6de1\u5165\u6548\u679c\n                    .duration(200)\n                    .style(\"opacity\", 0.95);\n            })\n            \/\/ \u9f20\u6807\u79fb\u51fa\uff1a\u9690\u85cftooltip\n            .on(\"mouseout\", function() {\n                tooltip.transition() \/\/ \u6de1\u51fa\u6548\u679c\n                    .duration(500)\n                    .style(\"opacity\", 0);\n            });\n\n        \/\/ \u6708\u4efd\u6807\u7b7e\n        const months = d3.timeMonths(startDate, endDate);\n        svg.selectAll(\".month-label\")\n            .data(months)\n            .enter().append(\"text\")\n            .attr(\"class\", \"month-label\")\n            .attr(\"x\", d =&gt; d3.timeWeek.count(d3.timeYear(d), d) * cellSize)\n            .attr(\"y\", 7 * cellSize + 20)\n            .attr(\"font-size\", \"11px\")\n            .attr(\"fill\", \"#666\")\n            .text(d =&gt; d3.timeFormat(\"%b\")(d));\n    };\n    &lt;\/script&gt;\n\n    &lt;style&gt;\n    .cell:hover {\n        stroke: #333 !important;\n        stroke-width: 1px !important;\n    }\n    &lt;\/style&gt;\n    &lt;?php\n    return ob_get_clean();\n}\nadd_shortcode('contribution_heatmap', 'contribution_heatmap_shortcode');\n?&gt;<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">\u9a8c\u8bc1\u6548\u679c\u662f\u5426\u751f\u6548<\/h1>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u65b0\u5efa \/ \u7f16\u8f91\u9875\u9762\uff0c\u5728\u7f16\u8f91\u5668\u4e2d\u8f93\u5165\u77ed\u4ee3\u7801<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>&#091;contribution_heatmap]<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u70b9\u51fb\u300c\u53d1\u5e03 \/ \u66f4\u65b0\u300d\uff0c\u524d\u53f0\u8bbf\u95ee\u9875\u9762\uff08\u6309<code>Ctrl+F5<\/code>\u5f3a\u5236\u6e05\u9664\u7f13\u5b58\uff09\u3002<\/li>\n\n\n\n<li>\u6b64\u65f6\u80fd\u770b\u5230\uff1a\n<ul class=\"wp-block-list\">\n<li>\u4e00\u4e2a\u5b8c\u6574\u7684 GitHub \u98ce\u683c\u65e5\u5386\u70ed\u529b\u56fe\uff0c\u6a2a\u5411\u6392\u5217\u6708\u4efd\uff0c\u7eb5\u5411\u6392\u5217\u661f\u671f\u3002 <\/li>\n\n\n\n<li>\u6709\u6587\u7ae0\u7684\u65e5\u671f\u663e\u793a\u5bf9\u5e94\u7eff\u8272\uff08\u6587\u7ae0\u6570\u8d8a\u591a\u989c\u8272\u8d8a\u6df1\uff09\uff0c\u65e0\u6587\u7ae0\u7684\u65e5\u671f\u663e\u793a\u767d\u8272\u3002<\/li>\n\n\n\n<li> \u9f20\u6807\u60ac\u6d6e\u5728\u65b9\u5757\u4e0a\uff0c\u4f1a\u663e\u793a\u5177\u4f53\u65e5\u671f\u548c\u521b\u4f5c\u6587\u7ae0\u6570\u3002 <\/li>\n\n\n\n<li>\u53f3\u4fa7\u6709\u6d3b\u8dc3\u5ea6\u989c\u8272\u68af\u5ea6\u8bf4\u660e\uff0c\u5e03\u5c40\u6574\u9f50\u7f8e\u89c2\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\n    <div id=\"contribution-wrapper\" style=\"width: 800px; margin: 20px 0;\">\n        <!-- \u53f3\u4e0a\u89d24\u7ea7\u8272\u5757\u56fe\u4f8b -->\n        <div id=\"heatmap-legend\" style=\"display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-bottom: 10px;\">\n            <span style=\"font-size: 0.9rem; color: #666;\">\u4e0d\u6d3b\u8dc3<\/span>\n            <div style=\"width: 20px; height: 20px; background: #ffffff; border: 1px solid #e0e0e0;\"><\/div>\n            <div style=\"width: 20px; height: 20px; background: #c8e6c9; border: 1px solid #e0e0e0;\"><\/div>\n            <div style=\"width: 20px; height: 20px; background: #66bb6a; border: 1px solid #e0e0e0;\"><\/div>\n            <div style=\"width: 20px; height: 20px; background: #2e7d32; border: 1px solid #e0e0e0;\"><\/div>\n            <span style=\"font-size: 0.9rem; color: #666;\">\u6d3b\u8dc3<\/span>\n        <\/div>\n\n        <!-- \u70ed\u529b\u56fe\u5bb9\u5668 -->\n        <div id=\"contribution-heatmap\" style=\"width: 100%; height: 250px; padding: 20px; border: 1px solid #ddd;\">\n            <div id=\"full-calendar\" style=\"width: 100%; height: 100%;\"><\/div>\n        <\/div>\n    <\/div>\n\n    <script src=\"https:\/\/cdn.bootcdn.net\/ajax\/libs\/d3\/7.8.5\/d3.min.js\"><\/script>\n    <script>\n    window.onload = function() {\n        if (!d3) {\n            document.getElementById(\"contribution-heatmap\").innerHTML = \"D3\u52a0\u8f7d\u5931\u8d25\";\n            return;\n        }\n\n        const contributionData = {\"2026-05-28\":1,\"2026-05-27\":1,\"2026-05-22\":1,\"2026-05-19\":2,\"2026-05-18\":1,\"2026-05-17\":1,\"2026-05-15\":1,\"2026-05-09\":1,\"2026-05-07\":1,\"2026-05-06\":1,\"2026-04-30\":1,\"2026-04-29\":1,\"2026-04-28\":1,\"2026-04-27\":1,\"2026-04-26\":1,\"2026-04-24\":1,\"2026-04-22\":1,\"2026-04-21\":1,\"2026-04-20\":1,\"2026-04-19\":1,\"2026-04-17\":1,\"2026-04-16\":1,\"2026-04-15\":1,\"2026-04-14\":1,\"2026-04-12\":1,\"2026-04-11\":1,\"2026-04-10\":2,\"2026-04-09\":2,\"2026-04-08\":2,\"2026-04-07\":2,\"2026-04-06\":1,\"2026-04-04\":1,\"2026-04-03\":2,\"2026-04-02\":2,\"2026-04-01\":2,\"2026-03-30\":1,\"2026-03-29\":1,\"2026-03-28\":1,\"2026-03-27\":1,\"2026-03-26\":1,\"2026-03-25\":1,\"2026-03-24\":1,\"2026-03-23\":1,\"2026-03-22\":1,\"2026-03-21\":1,\"2026-03-20\":1,\"2026-03-19\":1,\"2026-03-18\":1,\"2026-03-17\":1,\"2026-03-16\":1,\"2026-03-15\":1,\"2026-03-14\":1,\"2026-03-13\":1,\"2026-03-12\":1,\"2026-03-11\":1,\"2026-03-10\":1,\"2026-03-09\":1,\"2026-03-08\":1,\"2026-03-07\":1,\"2026-03-06\":1,\"2026-03-05\":1,\"2026-03-04\":1,\"2026-03-03\":1,\"2026-03-02\":1,\"2026-03-01\":1,\"2026-02-28\":1,\"2026-02-27\":1,\"2026-02-26\":1,\"2026-02-25\":1,\"2026-02-24\":1,\"2026-02-19\":1,\"2026-02-18\":1,\"2026-02-17\":1,\"2026-02-16\":1,\"2026-02-15\":1,\"2026-02-14\":1,\"2026-02-13\":1,\"2026-02-12\":2,\"2026-02-11\":2,\"2026-02-10\":3,\"2026-02-09\":2,\"2026-02-07\":1,\"2026-02-06\":5,\"2026-02-05\":5,\"2026-02-04\":5,\"2026-02-03\":5,\"2026-02-02\":4,\"2026-02-01\":5,\"2026-01-31\":5,\"2026-01-30\":2,\"2026-01-29\":1,\"2026-01-27\":1};\n        const startDate = new Date(\"2026\", 0, 1);\n        const endDate = new Date(\"2026\", 11, 31);\n        const today = new Date(); \/\/ \u83b7\u53d6\u5f53\u524d\u65e5\u671f\uff08\u7528\u4e8e\u533a\u5206\u8fc7\u53bb\/\u672a\u6765\uff09\n        today.setHours(0, 0, 0, 0); \/\/ \u91cd\u7f6e\u65f6\u95f4\u4e3a0\u70b9\uff0c\u907f\u514d\u65f6\u5206\u79d2\u5e72\u6270\u65e5\u671f\u5224\u65ad\n        const dateRange = d3.timeDays(startDate, endDate);\n        const cellSize = 14;\n        const margin = { top: 20, right: 10, bottom: 30, left: 10 };\n\n        \/\/ ******** \u65b0\u589e1\uff1a\u521b\u5efatooltip\u5143\u7d20\uff08\u9ed8\u8ba4\u9690\u85cf\uff09 ********\n        const tooltip = d3.select(\"body\").append(\"div\")\n            .attr(\"class\", \"heatmap-tooltip\")\n            .style(\"position\", \"absolute\")\n            .style(\"background-color\", \"#ffffff\")\n            .style(\"border\", \"1px solid #e0e0e0\")\n            .style(\"border-radius\", \"4px\")\n            .style(\"padding\", \"6px 10px\")\n            .style(\"font-size\", \"0.9rem\")\n            .style(\"box-shadow\", \"0 2px 5px rgba(0, 0, 0, 0.1)\")\n            .style(\"opacity\", 0) \/\/ \u9ed8\u8ba4\u900f\u660e\u9690\u85cf\n            .style(\"pointer-events\", \"none\") \/\/ \u4e0d\u963b\u6321\u9f20\u6807\u4e8b\u4ef6\n            .style(\"z-index\", \"9999\"); \/\/ \u786e\u4fdd\u5728\u6700\u4e0a\u5c42\n\n        \/\/ \u521b\u5efaSVG\u5bb9\u5668\n        const svg = d3.select(\"#full-calendar\")\n            .append(\"svg\")\n            .attr(\"width\", \"100%\")\n            .attr(\"height\", \"100%\")\n            .append(\"g\")\n            .attr(\"transform\", `translate(${margin.left}, ${margin.top})`);\n\n        \/\/ ******** \u65b0\u589e2\uff1a\u65e5\u671f\u683c\u5f0f\u5316\u51fd\u6570\uff082026-01-26 Mon\uff09 ********\n        const dateFormatter = d3.timeFormat(\"%Y-%m-%d %a\"); \/\/ %Y=\u5e74, %m=\u6708, %d=\u65e5, %a=\u661f\u671f\u7f29\u5199\uff08Mon\/Tue\u7b49\uff09\n\n        \/\/ \u70ed\u529b\u56fe\u989c\u8272\uff1a\u4e0e4\u7ea7\u56fe\u4f8b\u5bf9\u5e94\n        const cells = svg.selectAll(\".cell\")\n            .data(dateRange)\n            .enter().append(\"rect\")\n            .attr(\"class\", \"cell\")\n            .attr(\"width\", cellSize - 1)\n            .attr(\"height\", cellSize - 1)\n            .attr(\"x\", d => d3.timeWeek.count(d3.timeYear(d), d) * cellSize)\n            .attr(\"y\", d => d3.timeFormat(\"%w\")(d) * cellSize)\n            .attr(\"fill\", d => {\n                const dateStr = d3.timeFormat(\"%Y-%m-%d\")(d);\n\t\t\t\t\t\tconst articleCount = contributionData[dateStr] || 0;\n                if (articleCount >= 5) return \"#2e7d32\"; \/\/ \u7b49\u7ea74\uff08\u6d3b\u8dc3\uff09\n                if (articleCount >= 3) return \"#66bb6a\"; \/\/ \u7b49\u7ea73\n                if (articleCount >= 1) return \"#c8e6c9\"; \/\/ \u7b49\u7ea72\n                return \"#ffffff\"; \/\/ \u7b49\u7ea71\uff08\u4e0d\u6d3b\u8dc3\uff09\n            })\n            .attr(\"stroke\", \"#f0f0f0\");\n\n        \/\/ ******** \u65b0\u589e3\uff1a\u9f20\u6807\u60ac\u6d6e\u4e8b\u4ef6\uff08\u533a\u5206\u8fc7\u53bb\/\u672a\u6765\u65e5\u671f\uff09 ********\n        cells\n            \/\/ \u9f20\u6807\u79fb\u5165\uff1a\u663e\u793atooltip\n            .on(\"mouseover\", function(event, d) {\n                \/\/ 1. \u683c\u5f0f\u5316\u65e5\u671f\u4e3a\u300c2026-01-26 Mon\u300d\u683c\u5f0f\n                const formattedDate = dateFormatter(d);\n                \/\/ 2. \u91cd\u7f6e\u5f53\u524d\u65e5\u671f\u7684\u65f6\u5206\u79d2\uff08\u907f\u514d\u65f6\u5206\u79d2\u5e72\u6270\u5224\u65ad\uff09\n                const cellDate = new Date(d);\n                cellDate.setHours(0, 0, 0, 0);\n\n                \/\/ 3. \u533a\u5206\u300c\u8fc7\u53bb\/\u5f53\u524d\u65e5\u671f\u300d\u548c\u300c\u672a\u6765\u65e5\u671f\u300d\n                let tooltipContent = \"\";\n                if (cellDate <= today) {\n                    \/\/ \u8fc7\u53bb\/\u5f53\u524d\u65e5\u671f\uff1a\u663e\u793a\u300c\u65e5\u671f + \u6587\u7ae0\u6570\u300d\n                    const dateStr = d3.timeFormat(\"%Y-%m-%d\")(d);\n                    const articleCount = contributionData[dateStr] || 0;\n                    tooltipContent = `${formattedDate}<br>\u521b\u4f5c\u6587\u7ae0\uff1a${articleCount} \u7bc7`;\n                } else {\n                    \/\/ \u672a\u6765\u65e5\u671f\uff1a\u53ea\u663e\u793a\u300c\u65e5\u671f\u300d\n                    tooltipContent = formattedDate;\n                }\n\n                \/\/ 4. \u663e\u793atooltip\u5e76\u8c03\u6574\u4f4d\u7f6e\uff08\u8ddf\u968f\u9f20\u6807\uff09\n                tooltip.html(tooltipContent)\n                    .style(\"left\", (event.pageX + 10) + \"px\") \/\/ \u9f20\u6807\u53f3\u4fa710px\n                    .style(\"top\", (event.pageY - 20) + \"px\") \/\/ \u9f20\u6807\u4e0a\u65b920px\n                    .transition() \/\/ \u6de1\u5165\u6548\u679c\n                    .duration(200)\n                    .style(\"opacity\", 0.95);\n            })\n            \/\/ \u9f20\u6807\u79fb\u51fa\uff1a\u9690\u85cftooltip\n            .on(\"mouseout\", function() {\n                tooltip.transition() \/\/ \u6de1\u51fa\u6548\u679c\n                    .duration(500)\n                    .style(\"opacity\", 0);\n            });\n\n        \/\/ \u6708\u4efd\u6807\u7b7e\n        const months = d3.timeMonths(startDate, endDate);\n        svg.selectAll(\".month-label\")\n            .data(months)\n            .enter().append(\"text\")\n            .attr(\"class\", \"month-label\")\n            .attr(\"x\", d => d3.timeWeek.count(d3.timeYear(d), d) * cellSize)\n            .attr(\"y\", 7 * cellSize + 20)\n            .attr(\"font-size\", \"11px\")\n            .attr(\"fill\", \"#666\")\n            .text(d => d3.timeFormat(\"%b\")(d));\n    };\n    <\/script>\n\n    <style>\n    .cell:hover {\n        stroke: #333 !important;\n        stroke-width: 1px !important;\n    }\n    <\/style>\n    <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5b9e\u73b0\u4e0b\u9762\u8fd9\u79cd\u7c7b\u4f3c GitHub \u8d21\u732e\u70ed\u529b\u56fe\u7684\u300c\u521b\u4f5c\u6307\u6570\u65e5\u5386\u300d \u4fee\u6539\u5b50\u4e3b\u9898functions.php\u4ee3\u7801 \u9a8c\u8bc1\u6548<\/p>\n<div class=\"more-link\">\n\t\t\t\t <a href=\"https:\/\/yunyanglib.cn\/?p=113\" class=\"link-btn theme-btn\"><span>Read More <\/span> <i class=\"fa fa-caret-right\"><\/i><\/a>\n\t\t\t<\/div>\n","protected":false},"author":1,"featured_media":156,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[13],"class_list":["post-113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-website-construction","tag-web-devement"],"_links":{"self":[{"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/posts\/113","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=113"}],"version-history":[{"count":13,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/posts\/113\/revisions"}],"predecessor-version":[{"id":246,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/posts\/113\/revisions\/246"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=\/wp\/v2\/media\/156"}],"wp:attachment":[{"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yunyanglib.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}