
The Anchorage
Personal website of Gregory K. Maxey, Commander USN (Retired)
The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.
However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.
If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!
The purpose of this Microsoft Word Tips & Microsoft Word Help page is to publish a collection of VBA procedures (macros) useful for working with the Word field collection.
I love Word fields. They are a semi-advanced Word feature and with the exception of VBA, I think that they are the most powerful and useful feature in the application. For more on Word fields in general, see my: Word Fields
Before getting to the specific field macros, I think it is important to review a few technical issues (or perhaps quirks) associated with using VBA procedures in general and using them with the field collection in particular.
Many of you are familiar with Word's Find or Find and Replace feature. It has probably saved millions of people countless hours in document preparation and editing. Seemingly by magic it can find anything and replace it with anything else.
If you record a macro of running a Find and Replace operation and then run that macro, the magic of Find and Replace seems to have lost some of the shine.
Note: A full discussion of the issue addressed above is available at: Using a Macro to Replace Text Wherever It Appears in a Document
Accepting the issues discussed above, my approach to employing Word field macros is to start with a "universal" procedure that will process the entire document. With this as the starting point I can then insert calls to specific "actionable" procedures that act on the targeted fields. The basic universal procedure is provided below.
Public Sub UniversalFieldMacro() Dim rngStory As Word.Range Dim lngLink As Long Dim oShp As Shape lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Do On Error Resume Next 'Insert call to action procedure here Select Case rngStory.StoryType Case 6, 7, 8, 9, 10, 11 If rngStory.ShapeRange.Count > 0 Then For Each oShp In rngStory.ShapeRange If oShp.TextFrame.HasText Then 'Insert call to action procedure here End If Next End If Case Else 'Do Nothing End Select On Error GoTo 0 'Get next linked story (if any) Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next rngStory lbl_Exit: Exit Sub End Sub
See: Installing Macros for instructions on how to set up and use the macros provided in this Microsoft Word Help & Microsoft Word Tips page.
If you study the code
, you should see that each stroyrange, linked storyrange and troubled shape TextFrame is processed and a Word field will have nowhere to hide.
Fields are an object and therefore a countable item in any given range. If you pass a range containing one or more fields as an argument to a VBA procedure, you can then delete all of the fields contained in that range.
Sub FieldsDeleteAll(ByRef oTargetRng As Range)
With oTargetRng.Fields
While .Count > 0
.Item(1).Delete
Wend
End With
lbl_Exit:
Exit Sub
End Sub
Combining the procedure above with the universal field macro, you can delete all fields in a document.
Public Sub UniversalFieldMacro() Dim rngStory As Word.Range Dim lngLink As Long Dim oShp As Shape lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each rngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Do On Error Resume Next 'Call actionable procedure FieldsDeleteAll rngStory Select Case rngStory.StoryType Case 6, 7, 8, 9, 10, 11 If rngStory.ShapeRange.Count > 0 Then For Each oShp In rngStory.ShapeRange If oShp.TextFrame.HasText Then 'Call actionable procedure FieldsDeleteAll oShp.TextFrame.TextRange End If Next End If Case Else 'Do Nothing End Select On Error GoTo 0 'Get next linked story (if any) Set rngStory = rngStory.NextStoryRange Loop Until rngStory Is Nothing Next rngStory lbl_Exit: Exit Sub End Sub Sub FieldsDeleteAll(ByRef oTargetRng As Range) With oTargetRng.Fields While .Count > 0 .Item(1).Delete Wend End With lbl_Exit: Exit Sub End Sub
Perhaps you don't want to delete all fields. You may only want to delete a particular type field. To do this you simply create an actionable procedure targeting only a specific field (or fields)and call it using the universal macro.
Sub DeleteAllSpecificFields(ByRef oTargetRng As Range)
Dim oFld As Word.Field
For Each oFld In oTargetRng.Fields
Select Case oFld.Type
Case wdFieldPage
oFld.Delete
Case Else
'Do nothing
End Select
Next oFld
lbl_Exit:
Exit Sub
End Sub
Then there is the case when you may only want to delete fields in specific storyrange (e.g., headers or footers). It can start to get complicated, but again you can use the universal macro to call a carefully crafted actionable procedure.
Public Sub UniversalFieldMacro()
Dim rngStory As Word.Range
Dim lngLink As Long
Dim oShp As Shape
lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType
For Each rngStory In ActiveDocument.StoryRanges
'Iterate through all linked stories
Do
On Error Resume Next
'Call actionable procedure
'FieldsDeleteAll rngStory
'DeleteAllSpecificFields rngStory
DeleteAllSpecificFieldsInSpecifStoryRange rngStory, wdPrimaryFooterStory
Select Case rngStory.StoryType
Case 6, 7, 8, 9, 10, 11
If rngStory.ShapeRange.Count > 0 Then
For Each oShp In rngStory.ShapeRange
If oShp.TextFrame.HasText Then
'Call actionable procedure
'FieldsDeleteAll oShp.TextFrame.TextRange
'DeleteAllSpecificFields rngStory
End If
Next
End If
Case Else
'Do Nothing
End Select
On Error GoTo 0
'Get next linked story (if any)
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next rngStory
lbl_Exit:
Exit Sub
End Sub
Sub DeleteAllSpecificFieldsInSpecifStoryRange(ByRef oTargetRng As Range, lngStoryType As Long)
Dim oFld As Field
Dim oShp As Shape
Select Case oTargetRng.StoryType
Case lngStoryType
For Each oFld In oTargetRng.Fields
Select Case oFld.Type
Case wdFieldPage
oFld.Delete
Case Else
'Do nothing
End Select
Next oFld
Select Case lngStoryType
Case 6, 7, 8, 9, 10, 11
If oTargetRng.ShapeRange.Count > 0 Then
For Each oShp In oTargetRng.ShapeRange
If oShp.TextFrame.HasText Then
For Each oFld In oShp.TextFrame.TextRange.Fields
Select Case oFld.Type
Case wdFieldPage
oFld.Delete
Case Else
'Do nothing
End Select
Next oFld
End If
Next oShp
End If
Case Else
'Do nothing
End Select
Case Else
'Do nothing
End Select
lbl_Exit:
Exit Sub
End Sub
In the code posted above, notice in the universal macro that the actionable procedure is only called in the main For Each rngStory ... Next loop and not repeated in the For Each oShp ...
Next loop. This is because shaped (even shapes in the header and footers have their own storytype definition). Processing of the header and footer storyrange shapes is incorporated in the actionable procedure.
Some Word fields themselves target a collection. For example, the DocProperty field shown below returns the value of a targeted property "Author" in the document properties collection.

If you need to target a specific target in a specific field then you can use a customized VBA procedure to peel back another layer of the onion and look a the field code.
Given the unlikelihood that the field used in this example will be located in a shape in the header or footer, I've simplified the procedure by eliminating the code required to handle that situation.
Sub TargetSpecificTargetInSpecificFields()
Dim rngStory As Word.Range
Dim oFld As Word.Field
Dim lngLink As Long
lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType
For Each rngStory In ActiveDocument.StoryRanges
Do
For Each oFld In rngStory.Fields
Select Case oFld.Type
Case wdFieldDocProperty
'Dig a little deeper and see what the field code contains.
If InStr(oFld.Code.Text, "Author") Then
oFld.Unlink
End If
Case Else
'Do nothing
End Select
Next
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next
lbl_Exit:
Exit Sub
End Sub
This section shows you how you can target all fields with a general actionable procedure and delete, lock, unlink, update, or unlock all fields in a document using the universal field macro.
Sub FieldsActionAll(ByRef oTargetRng As Range, strAction As String, Optional bLocked As Boolean = False) 'Action is passed as an argument by the calling universal field macro. 'Example calls: 1. In the For Each rngStory ... Next loop: FieldsActionAll rngStory, "Update" 2. In the For Each oShp ... Next loop: oShp.TextFrame.TextRange, "Update" Select Case strAction Case "Update" oTargetRng.Fields.Update Case "Unlink" oTargetRng.Fields.Unlink Case "Locked" 'Takes the optional argument oTargetRng.Fields.Locked = bLocked 'You can pass "Delete" too!! Case "Delete" With oTargetRng.Fields While .Count > 0 .Item(1).Delete Wend End With End Select lbl_Exit: Exit Sub End Sub
Note: You should see that the actionable procedure shown eliminates the need for a specific actionable procedure Sub FieldsDeleteAll() demonstrated earlier!!
In the previous examples you saw how the universal field macro was used to call and pass arguments to the actionable procedures. Taking this a step further, you can call and pass arguments to the universal field macro making it the middle man for one or more field actions you may want to perform.
For example, I've assigned the keyboard shortcut F9 to the procedure FieldsUpdateAll shown below. By revising the UniversalFieldMacro to take an argument, I can simply press F9 and all fields in my document are updated.
Sub FieldsUpdateAll()
UniversalFieldMacro "Update"
lbl_Exit:
Exit Sub
End Sub
Public Sub UniversalFieldMacro(ByRef strAction As String)
Dim rngStory As Word.Range
Dim lngLink As Long
Dim oShp As Shape
lngLink = ActiveDocument.Sections(1).Headers(1).Range.StoryType
For Each rngStory In ActiveDocument.StoryRanges
'Iterate through all linked stories
Do
On Error Resume Next
'Call actionable procedure
FieldsActionAll rngStory, strAction
Select Case rngStory.StoryType
Case 6, 7, 8, 9, 10, 11
If rngStory.ShapeRange.Count > 0 Then
For Each oShp In rngStory.ShapeRange
If oShp.TextFrame.HasText Then
'Call actionable procedure
FieldsActionAll oShp.TextFrame.TextRange, strAction
End If
Next
End If
Case Else
'Do Nothing
End Select
On Error GoTo 0
'Get next linked story (if any)
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next rngStory
lbl_Exit:
Exit Sub
End Sub
I'll use this space to post custom field macros that I've created or found interesting.
Public Sub ConstructFieldsWithVBA()
Dim oRng As Range
Dim oFooterRng1 As Range
Dim oFooterRng2 As Range
Set oRng = ActiveDocument.Sections(1).Footers(wdHeaderFooterPrimary).Range
With oRng
.Text = "IF PAGE = ""1""""""PAGE"
Set oFooterRng1 = .Duplicate
Set oFooterRng2 = .Duplicate
End With
'Insert the field code around the complete expression
fInsertFields oFooterRng1, "IF PAGE = ""1""""""PAGE"
'Insert the field code around the Page expressions
fInsertFields oFooterRng2, "PAGE"
oRng.Fields.Update
ActiveWindow.View.ShowFieldCodes = False
lbl_Exit:
Exit Sub
End Sub
Public Sub fInsertFields(oRng As Range, Optional strText As String)
With oRng
'Find the expression and add a field around it
With .Find
.Text = strText
.MatchCase = True
While .Execute
oRng.Fields.Add oRng, wdFieldEmpty, , False
oRng.Collapse wdCollapseEnd
Wend
End With
End With
lbl_Exit:
Exit Sub
End Sub
That's it for now! I hope you have found this tips page useful and informative. You can download a Word 2003 document containing all the code examples shown above: Field Macros.
The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.
However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.
If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!